diff --git a/README_cn.md b/README_cn.md index a5db3ace61901b3c982816a4eccc636400d438d0..b2a60213a138aa33f8b2bee6cd87c84ebf30fddf 100644 --- a/README_cn.md +++ b/README_cn.md @@ -67,7 +67,6 @@ openGauss JDBC 驱动的生成支持以下操作系统: | maven | 3.6.1 | | java | 1.8 | | Git Bash (Windows) | 无推荐版本 | -| zip/unzip (Windows) | 无推荐版本 | ### 下载openGauss-connector-jdbc源码 @@ -82,89 +81,42 @@ git clone https://gitee.com/opengauss/openGauss-connector-jdbc.git - /sda/openGauss-connector-jdbc -### 编译第三方软件(可跳过) - -在构建openGauss-connector-jdbc之前,需要先编译openGauss依赖的开源及第三方软件。我们已经在openGauss-connector-jdbc目录下的open_source就提供了编译好的开源及第三方软件,直接使用我们提供的open_source可以跳过该部分。这些开源及第三方软件存储在openGauss-third_party代码仓库中,通常只需要构建一次。如果开源软件有更新,需要重新构建软件。 - -用户也可以直接从**binarylibs**库中获取开源软件编译和构建的输出文件。 - -如果你想自己编译第三方软件,请到openGauss-third_party仓库查看详情。 - -执行完上述脚本后,最终编译和构建的结果保存在与**openGauss-third_party**同级的**binarylibs**目录下。在编译**openGauss-connector-jdbc**时会用到这些文件。 - ### jar包生成 -#### 使用一键式脚本生成jar包(Linux) +#### 使用一键式脚本生成jar包(Linux/windows) openGauss-connector-jdbc中的build.sh是编译过程中的重要脚本工具。该工具可快速进行代码编译和打包。 -参数说明请见以下表格。 - -| 选项 | 缺省值 | 参数 | 说明 | -| :--- | :--------------------------- | :---------------- | :----------------------------------------------------------- | -| -3rd | ${Code directory}/binarylibs | [binarylibs path] | 指定binarylibs路径。建议将该路径指定为open_source/或者/sda/openGauss-connector-jdbc/open_source/。如果您有自己编译好openGauss依赖的的第三方库,也可以指定为编译好的三方库路径,如/sda/binarylibs。 | - -> **注意** -> -> - **-3rd [binarylibs path]**为**binarylibs**的路径。默认设置为当前代码文件夹下存在**binarylibs**,因此如果**binarylibs**被移至**openGauss-server**中,或者在**openGauss-server**中创建了到**binarylibs**的软链接,则不需要指定此参数。但请注意,这样做的话,该文件很容易被**git clean**命令删除。 - -现在你已经知晓build.sh的用法,只需使用如下格式的命令即可编译openGauss-connector-jdbc。 +只需使用如下格式的命令即可编译openGauss-connector-jdbc。 1. 执行如下命令进入到代码目录: ``` - [user@linux sda]$ cd /sda/openGauss-connector-jdbc + [user@linux sda]$ cd /sda/openGauss-connector-jdbc/ ``` 2. 执行如下命令使用build.sh进行打包: ``` - [user@linux openGauss-connector-jdbc]$ sh build.sh -3rd open_source/ + [user@linux openGauss-connector-jdbc]$ sh build.sh ``` 结束后会显示如下内容,表示打包成功: ``` Successfully make postgresql.jar - opengauss-jdbc-${version}.jar - postgresql.jar - Successfully make jdbc jar package + 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**。 -#### 使用一键式脚本生成jar包(Windows) - -1. 准备 Java 与 Maven环境, 以及可以在**Git Bash**中使用的 **zip/unzip** 命令。 - -2. 执行如下命令进入到代码目录: - - ``` - [user@linux openGauss-connector-jdbc]$ cd /sda/openGauss-connector-jdbc - ``` - -3. 运行脚本build_on_windows_git.sh: - - ``` - [user@linux openGauss-connector-jdbc]$ sh build_on_windows_git.sh - ``` - - 脚本执行成功后,会显示如下结果: - - ``` - begin run - Successfully make postgresql.jar package in /sda/openGauss-connector-jdbc/output/postgresql.jar - Successfully make opengauss-jdbc jar package in /sda/openGauss-connector-jdbc/output/opengauss-jdbc-${version}.jar - Successfully make jdbc jar package in /sda/openGauss-connector-jdbc/openGauss-${version}-JDBC.tar.gz - ``` - - 成功编译后会出现两个jar包,分别是opengauss-jdbc-${version}.jar与postgresql.jar。编译后的jar包路径为:**/sda/openGauss-connector-jdbc/output/**。此外还会出现这两个jar包的压缩包openGauss-${version}-JDBC.tar.gz,压缩包路径为 **/sda/openGauss-connector-jdbc/**。 - - #### 使用mvn命令生成jar包(Windows 或 Linux) -1. 准备 Java 与 Maven环境, 若在Windows环境下还需准备可以在**Git Bash**中使用的 **zip/unzip** 命令。 +1. 准备 Java 与 Maven环境。 2. 执行如下命令进入到代码目录: @@ -172,26 +124,10 @@ openGauss-connector-jdbc中的build.sh是编译过程中的重要脚本工具。 [user@linux sda]$ cd /sda/openGauss-connector-jdbc ``` -3. 使用demo准备脚本: +3. 执行mvn命令: ``` - [user@linux openGauss-connector-jdbc]$ sh prepare_demo.sh - ``` - -4. 修改根目录下的pom.xml: - - 将modules部分的module由jdbc改为pgjdbc, 如下所示。 - - ``` - - pgjdbc - - ``` - -5. 执行mvn命令: - - ``` - [user@linux openGauss-connector-jdbc]$ mvn clean install -Dmaven.test.skip=true + [user@linux openGauss-connector-jdbc]$ mvn clean install -Dgpg.skip -Dmaven.test.skip=true ``` Linux系统下构建成功后会显示如下结果: @@ -211,7 +147,7 @@ openGauss-connector-jdbc中的build.sh是编译过程中的重要脚本工具。 ``` 构建成功后会出现两个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的使用 diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000000000000000000000000000000000000..382ba451253eb10557bb4b964d44d1e19db96872 --- /dev/null +++ b/README_en.md @@ -0,0 +1,200 @@ +![openGauss Logo](https://opengauss.org/img/brand/view/logo2.jpg) + + + +## 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/build.sh b/build.sh old mode 100755 new mode 100644 index 885b252a13e9a84fba986d9607bb41121d742bef..a9bebb5ebbf7880b2634853b1d81c4a7f1c98c60 --- a/build.sh +++ b/build.sh @@ -16,15 +16,12 @@ # ---------------------------------------------------------------------------- # Description : shell script for jdbc package. ############################################################################# +set -e BUILD_FAILED=1 -java_path="" -ant_path="" JDBC_DIR=$(dirname $(readlink -f $0)) LOG_FILE=$JDBC_DIR/logfile -THIRD_DIR=$JDBC_DIR/buildtools -libs=$JDBC_DIR/libs -NOTICE_FILE='Copyright Notice.doc' +ARCH=$(uname -m) #detect platform information. PLATFORM=32 bit=$(getconf LONG_BIT) @@ -43,6 +40,9 @@ elif [ -f "/etc/openEuler-release" ]; then elif [ -f "/etc/centos-release" ]; then kernel=$(cat /etc/centos-release | awk -F ' ' '{print $1}' | tr A-Z a-z) version=$(cat /etc/centos-release | awk -F '(' '{print $2}'| awk -F ')' '{print $1}' | tr A-Z a-z) +elif [ -f "/etc/kylin-release" ]; then + kernel=$(cat /etc/kylin-release | awk -F ' ' '{print $1}' | tr A-Z a-z) + version=$(cat /etc/kylin-release | awk '{print $6}' | tr A-Z a-z) else kernel=$(lsb_release -d | awk -F ' ' '{print $2}'| tr A-Z a-z) version=$(lsb_release -r | awk -F ' ' '{print $2}') @@ -50,37 +50,27 @@ fi if [ X"$kernel" == X"euleros" ]; then dist_version="EULER" -elif [ X"$kernel" == X"centos" ]; then +elif [ X"$kernel" == X"centos" ]; then dist_version="CENTOS" -elif [ X"$kernel" == X"openeuler" ]; then +elif [ X"$kernel" == X"openeuler" ]; then dist_version="OPENEULER" +elif [ X"$kernel" == X"kylin" ]; then + dist_version="KYLIN" +elif [ X"$kernel" = X"suse" ]; then + dist_version="SUSE" else - echo "Only support EulerOS, OPENEULER(aarch64) and CentOS platform." - echo "Kernel is $kernel" - exit 1 + echo "WARN:Only EulerOS, OPENEULER(aarch64), SUSE, and CentOS platform support, there will set to UNKNOWN" + dist_version="UNKNOWN" fi -export PLAT_FORM_STR=$(sh "${JDBC_DIR}/get_PlatForm_str.sh") declare install_package_format='tar' -declare mppdb_version='GaussDB Kernel' -declare mppdb_name_for_package="$(echo ${mppdb_version} | sed 's/ /-/g')" -declare version_number='V500R001C20' +declare mppdb_name_for_package="openGauss" +pom_version_number=`awk '/[^<]+<\/version>/{gsub(/|<\/version>/,"",$1);print $1;exit;}' ${JDBC_DIR}/pgjdbc/pom.xml` +declare version_number="${pom_version_number}" declare version_string="${mppdb_name_for_package}-${version_number}" declare package_pre_name="${version_string}-${dist_version}-${PLATFORM}bit" declare jdbc_package_name="${package_pre_name}-Jdbc.${install_package_format}.gz" -coretype=$(uname -p) -mvn_name="apache-maven-3.6.3-bin.tar.gz" -jdk_name="OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz" - -if [ X"$coretype" == X"aarch64" ]; then - jdk_name="OpenJDK8U-jdk_aarch64_linux_hotspot_8u222b10.tar.gz" -fi - -tar -zxvf buildtools/$jdk_name -C buildtools/ > /dev/null -mkdir -p buildtools/maven -tar -zxvf buildtools/$mvn_name -C buildtools/maven/ > /dev/null - die() { echo "ERROR: $@" @@ -89,11 +79,7 @@ die() function prepare_java_env() { - echo "Prepare the build enviroment." - export JAVA_HOME=$THIRD_DIR/jdk8u222-b10 - export JRE_HOME=$JAVA_HOME/jre - export LD_LIBRARY_PATH=$JRE_HOME/lib/amd64/server:$LD_LIBRARY_PATH - export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH + echo "We no longer provide java, please makesure java(1.8*) already in PATH!" JAVA_VERSION=`java -version 2>&1 | awk -F '"' '/version/ {print $2}'` echo java version is $JAVA_VERSION } @@ -106,11 +92,11 @@ function prepare_env() function prepare_maven_env() { - export MAVEN_HOME=$THIRD_DIR/maven/apache-maven-3.6.3/ - export PATH=$MAVEN_HOME/bin:$PATH + echo "We no longer provide mvn, please makesure mvn(3.6.0+) already in PATH!" MAVEN_VERSION=`mvn -v 2>&1 | awk '/Apache Maven / {print $3}'` echo maven version is $MAVEN_VERSION } + function install_jdbc() { export JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8" @@ -122,24 +108,11 @@ function install_jdbc() echo "Begin make jdbc..." export CLASSPATH=".:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar" echo ${JDBC_DIR} - cd "${JDBC_DIR}/shade" - mvn clean install -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 - cd "${JDBC_DIR}/shade/target" - jar -xf demo-0.0.1-SNAPSHOT.jar - rm -rf "${JDBC_DIR}/shade/temp/" - mkdir -p "${JDBC_DIR}/shade/temp/" - cp -r ./com "${JDBC_DIR}/shade/temp/" - cd "${JDBC_DIR}/shade/temp" - find ./com -name "*" | sort |xargs zip demo-0.0.1-SNAPSHOT.jar >> "$LOG_FILE" 2>&1 - mvn install:install-file -Dfile=${JDBC_DIR}/shade/temp/demo-0.0.1-SNAPSHOT.jar -DgroupId=com.huawei -DartifactId=demo-0.0.1-SNAPSHOT -Dversion=0.0.1 -Dpackaging=jar - if [ $? -ne 0 ]; then - die "mvn install demo failed." - fi rm -rf "${JDBC_DIR}/jdbc" cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r cd "${JDBC_DIR}/jdbc" find . -name 'Driver.java' | xargs sed -i "s/@GSVERSION@/${GS_VERSION}/g" - mvn clean install -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 + mvn clean install -Dgpg.skip -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then die "mvn install driver failed." fi @@ -148,15 +121,15 @@ function install_jdbc() mkdir ${OUTPUT_DIR} fi cd ${OUTPUT_DIR} - rm -rf *.jar + rm -rf *.jar *.gz version=`awk '/[^<]+<\/version>/{gsub(/|<\/version>/,"",$1);print $1;exit;}' ${JDBC_DIR}/jdbc/pom.xml` mv ${JDBC_DIR}/jdbc/target/opengauss-jdbc-${version}.jar ./postgresql.jar echo "Successfully make postgresql.jar" - rm -rf "${JDBC_DIR}/jdbc" - cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r +# rm -rf "${JDBC_DIR}/jdbc" +# cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r cd "${JDBC_DIR}/jdbc" - find . -name 'Driver.java' | xargs sed -i "s/@GSVERSION@/${GS_VERSION}/g" +# find . -name 'Driver.java' | xargs sed -i "s/@GSVERSION@/${GS_VERSION}/g" find . -name 'Driver.java' | xargs sed -i "s/jdbc:postgresql:/jdbc:opengauss:/g" find . -name 'java.sql.Driver' | xargs sed -i "s#org\.postgresql#${OPENGAUSS_PACKAGE_NAME}#g" find . -name '*.java' -type f | xargs sed -i "s#org\.postgresql#${OPENGAUSS_PACKAGE_NAME}#g" @@ -168,23 +141,13 @@ function install_jdbc() die "fail to replace url name in BaseDataSource" fi - mvn clean install -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 + mvn clean install -Dgpg.skip -Dmaven.test.skip=true -U >> "$LOG_FILE" 2>&1 cp ${JDBC_DIR}/jdbc/target/opengauss-jdbc-${version}.jar ${OUTPUT_DIR}/ - echo "Successfully make opengauss-jdbc jar package" - - cd ${OUTPUT_DIR}/ - tar -zcvf ${JDBC_DIR}/openGauss-${version}-JDBC.tar.gz *.jar - echo "Successfully make jdbc jar package" + echo "Successfully make opengauss-jdbc-${version} jar package" } function clean() { - if [ -d "${JDBC_DIR}/shade/temp" ]; then - rm -rf "${JDBC_DIR}/shade/temp" - fi - if [ -d "${JDBC_DIR}/shade/target" ]; then - rm -rf "${JDBC_DIR}/shade/target" - fi if [ -d "${JDBC_DIR}/jdbc" ]; then rm -rf "${JDBC_DIR}/jdbc" fi @@ -192,6 +155,7 @@ function clean() rm -rf "${LOG_FILE}" fi } + function select_package_command() { @@ -212,56 +176,26 @@ function select_package_command() function make_package() { cd ${JDBC_DIR}/output - cp ${JDBC_DIR}/"${NOTICE_FILE}" ./ - select_package_command echo "packaging jdbc..." - $package_command "${jdbc_package_name}" ./gsjdbc4.jar "${NOTICE_FILE}" >> "$LOG_FILE" 2>&1 + $package_command "${jdbc_package_name}" *.jar >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then - die "$package_command ${jdbc_package_name} failed" + die "$package_command ${jdbc_package_name} failed" fi cp "${jdbc_package_name}" ../ - echo "$pkgname tools is ${jdbc_package_name} of ${JDBC_DIR} directory " >> "$LOG_FILE" 2>&1 - echo "success!" -} -function registerJars() -{ - for src in `find $third_part_lib -name '*.jar'` - do - cp $src $libs/ - done - echo "copy finished" - cd $libs - prepare_env - mvn install:install-file -Dfile=./commons-logging-1.2.jar -DgroupId=commons-logging -DartifactId=commons-logging -Dversion=1.2 -Dpackaging=jar - mvn install:install-file -Dfile=./commons-codec-1.11.jar -DgroupId=commons-codec -DartifactId=commons-codec -Dversion=1.11 -Dpackaging=jar - mvn install:install-file -Dfile=./httpclient-4.5.13.jar -DgroupId=org.apache.httpcomponents -DartifactId=httpclient -Dversion=4.5.13 -Dpackaging=jar - mvn install:install-file -Dfile=./httpcore-4.4.13.jar -DgroupId=org.apache.httpcomponents -DartifactId=httpcore -Dversion=4.4.13 -Dpackaging=jar - mvn install:install-file -Dfile=./fastjson-1.2.70.jar -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.2.70 -Dpackaging=jar - mvn install:install-file -Dfile=./joda-time-2.10.6.jar -DgroupId=joda-time -DartifactId=joda-time -Dversion=2.10.6 -Dpackaging=jar - mvn install:install-file -Dfile=./jackson-databind-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-databind -Dversion=2.11.2 -Dpackaging=jar - mvn install:install-file -Dfile=./jackson-core-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-core -Dversion=2.11.2 -Dpackaging=jar - mvn install:install-file -Dfile=./jackson-annotations-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-annotations -Dversion=2.11.2 -Dpackaging=jar - mvn install:install-file -Dfile=./slf4j-api-1.7.30.jar -DgroupId=org.slf4j -DartifactId=slf4j-api -Dversion=1.7.30 -Dpackaging=jar - mvn install:install-file -Dfile=./java-sdk-core-3.0.12.jar -DgroupId=com.huawei.apigateway -DartifactId=hw-java-sdk-core -Dversion=3.0.12 -Dpackaging=jar + echo "$package_command tools is ${jdbc_package_name} of ${JDBC_DIR} directory " >> "$LOG_FILE" 2>&1 + echo "Successfully make jdbc jar package in ${jdbc_package_name}" } + prepare_env -export third_part_lib="" -if [ ! -d "${libs}" ]; then -mkdir ${libs} -fi -case $1 in - -3rd | --3rd) - if [ ! -n "$2" ]; then - die "3rd should not be empty" - fi - third_part_lib="$2" - registerJars - ;; - *);; -esac install_jdbc -clean +make_package +if [ "$1" = "-n" ] ;then + echo "the temporary directory has not been cleaned up, please clean up by yourself!" +else + echo "clean up temporary directory!" + clean +fi echo "now, all packages has finished!" exit 0 diff --git a/build_on_windows_git.sh b/build_on_windows_git.sh deleted file mode 100644 index 6b68a5c170a96a7cc429dd29c912bee2caf145cb..0000000000000000000000000000000000000000 --- a/build_on_windows_git.sh +++ /dev/null @@ -1,16 +0,0 @@ -#/bin/bash -# this script is to use in windows git bash shell to build opengauss jdbc jar. -# you need build tools in window's PATH below: -# java mvn zip tar xargs -# after success build, the tar package in openGauss-2.0.0-JDBC.tar.gz -# or you can int output dir find postgresql.jar and opengauss-jdbc*.jar -# please notice: postgresql.jar is conflict with postgres database jdbc. -# if you want to compatibiliry use opengauss and pg database, use opengauss-jdbc*.jar instead. -# the driver string is jdbc:opengauss://, the driver class is:org.opengauss.Driver -JDBC_DIR=$(dirname $(readlink -f $0)) -cd $JDBC_DIR -sh prepare_maven.sh -cd $JDBC_DIR -sh prepare_demo.sh -cd $JDBC_DIR -sh prepare_windows_build.sh diff --git a/buildtools/OpenJDK8U-jdk_aarch64_linux_hotspot_8u222b10.tar.gz b/buildtools/OpenJDK8U-jdk_aarch64_linux_hotspot_8u222b10.tar.gz deleted file mode 100644 index 12a1cb40110c1155b4765a7f7ab7ffd65af2d02a..0000000000000000000000000000000000000000 Binary files a/buildtools/OpenJDK8U-jdk_aarch64_linux_hotspot_8u222b10.tar.gz and /dev/null differ diff --git a/buildtools/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz b/buildtools/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz deleted file mode 100644 index 403dae8a46d141ffeda6752d23e0f2ea5c503ae7..0000000000000000000000000000000000000000 Binary files a/buildtools/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz and /dev/null differ diff --git a/buildtools/README b/buildtools/README deleted file mode 100644 index f7cdc741263d0cc9c805827d06398dac93d64b3b..0000000000000000000000000000000000000000 --- a/buildtools/README +++ /dev/null @@ -1,6 +0,0 @@ -Download the MAVEN from https://mirror.bit.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz -The version shoud be 3.6.3. -Download the java x86-64 from https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jdk_x64_linux_hotspot_8u222b10.tar.gz -The version should be 1.8. -Download the java aarch64 from https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jdk_aarch64_linux_hotspot_8u222b10.tar.gz -The version should be 1.8. diff --git a/buildtools/apache-maven-3.6.3-bin.tar.gz b/buildtools/apache-maven-3.6.3-bin.tar.gz deleted file mode 100644 index 66fdd6d4c4e6fbe7e917c9c9992bcdce0f80f21e..0000000000000000000000000000000000000000 Binary files a/buildtools/apache-maven-3.6.3-bin.tar.gz and /dev/null differ diff --git a/certdir/README.md b/certdir/README.md deleted file mode 100644 index ff041e3c490e6308fcb34e2c11f17cf3589d85cf..0000000000000000000000000000000000000000 --- a/certdir/README.md +++ /dev/null @@ -1,44 +0,0 @@ -To run the SSL tests, the following properties are used: - -* certdir: directory where the certificates and keys are store -* enable_ssl_tests: enables SSL tests - -In order to configure PostgreSQL for SSL tests, the following changes should be applied: - -* Copy server/server.crt, server/server.key, and server/root.crt to $PGDATA directory -* In $PGDATA directory: chmod 0600 server.crt server.key root.crt -* Set ssl=on in postgresql.conf -* Set ssl_cert_file=server.crt in postgresql.conf -* Set ssl_key_file=server.key in postgresql.conf -* Set ssl_ca_file=root.crt in postgresql.conf -* Add databases for SSL tests. Note: sslinfo extension is used in tests to tell if connection is using SSL or not - - for db in hostssldb hostnossldb certdb hostsslcertdb; do - createdb $db - psql $db -c "create extension sslinfo" - done -* Add test databases to pg_hba.conf. If you do not overwrite the pg_hba.conf then remember to comment out all lines - starting with "host all". -* Uncomment enable_ssl_tests=true in ssltests.properties -* The username for connecting to postgres as specified in build.local.properties tests has to be "test". - -This directory contains example certificates generated by the following -commands: - -openssl req -x509 -newkey rsa:1024 -days 3650 -keyout goodclient.key -out goodclient.crt -#Common name is test, password is sslpwd - -openssl req -x509 -newkey rsa:1024 -days 3650 -keyout badclient.key -out badclient.crt -#Common name is test, password is sslpwd - -openssl req -x509 -newkey rsa:1024 -days 3650 -nodes -keyout badroot.key -out badroot.crt -#Common name is localhost -rm badroot.key - -openssl pkcs8 -topk8 -in goodclient.key -out goodclient.pk8 -outform DER -v1 PBE-MD5-DES -openssl pkcs8 -topk8 -in badclient.key -out badclient.pk8 -outform DER -v1 PBE-MD5-DES -cp goodclient.crt server/root.crt -cd server -openssl req -x509 -newkey rsa:1024 -nodes -days 3650 -keyout server.key -out server.crt -cp server.crt ../goodroot.crt -#Common name is localhost, no password diff --git a/certdir/badclient.crt b/certdir/badclient.crt deleted file mode 100644 index 4f37a71e51668ffa52a8b7298ea9160c14894268..0000000000000000000000000000000000000000 --- a/certdir/badclient.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3jCCAkegAwIBAgIJAIHg5fMq+z8aMA0GCSqGSIb3DQEBBQUAMFQxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3QwHhcNMTExMTEwMjE0MjI3WhcN -MjExMTA3MjE0MjI3WjBUMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0 -ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDEwR0 -ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbMINU6XwQ/0OSQ4xYRp0o -gYzzsaaGgZjBZEpRMCZkB+TPUD/yxDpyfcknsvsBQPQ0bqLLS9yqf5iS26jHGd4U -/nInOy5rjIKEbJMUgkbNWiuVl5q1K+GFuTEpjpdLI9NH5X+jL1CxH/h8+j8Mr2iX -s4C2gIFu6povShJiIwBNBQIDAQABo4G3MIG0MB0GA1UdDgQWBBQ6L/fB+7uwDN9q -T5Do9X4GIbJnxDCBhAYDVR0jBH0we4AUOi/3wfu7sAzfak+Q6PV+BiGyZ8ShWKRW -MFQxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3SCCQCB4OXzKvs/ -GjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAKq2Q+aE5eC04gW58pAt -pobnL/2L0JHCeLPsv0k/1vjulzjBuphbwaibZtiYWZSDKWL8Dvsg+khq7rEIY0W6 -xXGw5y2scRlCukQvseIxbHUoyOCAWJnoqr7d8MyxP2GlpqSDXHk9wEywZ/6f89oN -yudtXjoYuW8157tmvrX3D1yd ------END CERTIFICATE----- diff --git a/certdir/badclient.key b/certdir/badclient.key deleted file mode 100644 index efc9b6c0132c5148aadb108858abdb6e3ac8d72f..0000000000000000000000000000000000000000 --- a/certdir/badclient.key +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,95718EE22B89E019 - -78LEg7uq4krPR3C1sQVCiQsPIXroyoDzPHBFmI+ipEJq7obFACK9KROfUAaMlca8 -ZR1UhtQHCPK4TOG1qKjn8lxeKGLZA25Lcilw6QvZCfNyBa6JUp3cdwzUSv7/qE/Y -d/wlVAq71JbOmYsbEwunZlq+DO1AaL91N/2ANgSSC85uR0dye0iZ1C0OZzawMXkd -wXRrXb8c8RCH2gQ6V4aMartTZ/DQznA59+NEUYln5IMP4joRM0TTpcuv6oCq1UUw -o7xEQcwfBB0tKayxkBfgp8Jvrghzw0usSFt4ad9I4DF/V2izojZgYsnT7yGqsop6 -7jmPR9llYhDQIZd0V4NZziiRF2Dt/lyG0iUPZq5vlhLaI59FzMAxVSAJP6DrUHQD -L76TeGpQm2LRqWliDc+3AMTCKv0TP1IPbIWJrnLxnNf/C29adO+VSeQEQ0+tBU+/ -DE2GVsQ/xul+QyCwXiOce0pfERLuGjSu/kRa1ylAlrdH4+6vBD0ewuXXHv0eTSxB -Vi0vde5a9PzPUMUBkg6PS7IDYJmKm04fFPxx3y8GMlzbZYOYjTepkYMbayekybGK -fHVk9Z3lW5yzegaz8iJu/8le6Kn4Ox21FRG45domu1T+8eJuXPoiBUb290SUVuxh -VTQWhCA8ElmVCYfrbSnYL3naeqVL+Oc6by3VVhvgiqUuXQTZvKN7mkUOhiNbpz2H -iGLwlRj6wXEaS0qLb9NQc9H9Vv6ftj7UPa4FkiJjWhUW0WkA5sqtOKMjLzpsIZtR -dFb26NE65tk0lrywQrzMBFM6fk90VrMYyvwukZIJIKRLCBQaG24PLQ== ------END RSA PRIVATE KEY----- diff --git a/certdir/badclient.pk8 b/certdir/badclient.pk8 deleted file mode 100644 index cebb2d78fa02762050a5d1555d8c54b6f15b64f2..0000000000000000000000000000000000000000 Binary files a/certdir/badclient.pk8 and /dev/null differ diff --git a/certdir/badroot.crt b/certdir/badroot.crt deleted file mode 100644 index 88ffbcf766f52dee3ea6e2aaf4d8dcc102268641..0000000000000000000000000000000000000000 --- a/certdir/badroot.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC7zCCAligAwIBAgIJANwlio9cWdoXMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMTExMTAyMTQy -NTdaFw0yMTExMDcyMTQyNTdaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21l -LVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA055WKnuQ -i6RPdI3LEtx8ztXV7BuiYihPXCRYUahLyF4TAzNGfmqsdQhqUlqzr1P+nlqxh8sm -hZGS4NtGPaEjrbPgsBsTVg0XBKpH5yf2RIhBtvAaDG+cCFBjM+LJGzc4we59JkB6 -n1a/22iSFsCAm+BFBwHk6FqF7u2gGSUOrI0CAwEAAaOBvjCBuzAdBgNVHQ4EFgQU -rw3IpiBN56GCi44/goVmHlZdmJswgYsGA1UdIwSBgzCBgIAUrw3IpiBN56GCi44/ -goVmHlZdmJuhXaRbMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRl -MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxv -Y2FsaG9zdIIJANwlio9cWdoXMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -gYEAa08IbYDJsgc45mYG/mviionvhBGs9BS2YapZDIREc/vd0W4FIzHXh5oTJAdF -fkPjvHoczPuzGX8EKMBjANPs7h4Cd5xKSSE2Su+QwmZOxVg6eIeQwVZsY7SZFmkC -Y2XwdxWvk3VzLdjgj/McmSBp4/aJUGRP6f5ehnR4B1ykVss= ------END CERTIFICATE----- diff --git a/certdir/goodclient.crt b/certdir/goodclient.crt deleted file mode 100644 index a45ae6c1c75d16700941c5749cb6fec7f5f24b45..0000000000000000000000000000000000000000 --- a/certdir/goodclient.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3jCCAkegAwIBAgIJAM9GGWA8iSiIMA0GCSqGSIb3DQEBBQUAMFQxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3QwHhcNMTExMTEwMjE0MTQ3WhcN -MjExMTA3MjE0MTQ3WjBUMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0 -ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDEwR0 -ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCns68NbjKQAnHCpmN6amR1 -GdtliqiXDaCjoeBPpVXNQ/ZhqinP9gnDyRPXC5kPqw5/6GqNHcYJqg+IIS8G85Rq -t3Cs5ZL+JlEDAwd0CkD0Ey5h0oJNfN1bDhV2e/yqc831ElBGK6VItGqKopSUV2y/ -pNijOOdeMZ8GuktT+9mbAQIDAQABo4G3MIG0MB0GA1UdDgQWBBTE93pAIzHiFRFw -IU38WhnwXm03GzCBhAYDVR0jBH0we4AUxPd6QCMx4hURcCFN/FoZ8F5tNxuhWKRW -MFQxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3SCCQDPRhlgPIko -iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAKUsXLsp3i9Tsj1wp46R -4IkIjwWT1bN3+JOjmA9aqwEVcxTRSStAa5kfTQwc4QSAgHK1oFPsA8gsv3sftYmZ -MtvYrvba8cOPonuaCrvtJQMvKgv3d10S6esUGlW+5o3PVPUq5yQ7OaN5JHCDTZGS -phuxlq7//rNjvypX2hbKUj6z ------END CERTIFICATE----- diff --git a/certdir/goodclient.key b/certdir/goodclient.key deleted file mode 100644 index 37d2ac5ae090521af5e95d765b8bb8d170500a82..0000000000000000000000000000000000000000 --- a/certdir/goodclient.key +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,D2A0607D6E4CE1FD - -/RMZp/vNTiHiAqVGyByL9Zms7sFWECqpDof6X1jzex7JWi7cjTzKDZiVyqmDfUU3 -A2v8dbMFQfak4tfpeWqx+HPkVX/GNTFhTI/Ic48+d/9iETwu4d0uMHyrX97GDzWt -72NbBdby16s+Lwp7Gu5WQ2fUwJVagHAD4nrHBP5yjOStf6l8CWSiCUTJCfSYxtR4 -eH3NtnmNE6/E8yodoUJhkNQDcPhP+cbXv5waEYWpoOJQ9G78JeQ+MKI8AEz+19UA -vAJDrWBjEgxrKK17qqL8+gxm09RzOt5z4QACt8nsJUV80FCENwIxHOlF8ZXc3Nfz -7wX6+F8LEvDL2Tf4fEELcigHnlf3N5/8iRd0MmAiB+4lRW8tYY3TnSS7fVLTJ/RJ -C5xdTr80zrM2sgqKbWtPKMSiXWCZGT81FpJ+bne4KAC868sZ71SzG3QiEt72z+On -fIN0qB31V0wZB+ZCAU0Me138F9BH7rQALVM619f7OUDMEA2Mbnhej4eblqHnc1MY -/JS4HRa6OnSaQJs2KR2+zqadAa9Z1d3dJhVAZ0bPBJ43xCZDuv+33POv1fXJ21us -wcy+OrDyEWR27QpWWkOfwvc4txLqxQ4QlNqApIQYV4nWD220ZM9L49KSCqfG2VHN -vFhjLKTj/oMKJZll/V58Qc3JPj14FKJD5ODfg2LOFst/vA7UhkV1MRar8rlqzIBa -LGl4zgZCDlFlUmiymXmCSC6LrxD78oHT4EMJFk2fK/lAgW5i4E/qFGHUl8rCqNR3 -Lpo0YYC4hu5hh1aWuxUyMiXQrnCXTbrXj1svTksD/cTCwjRHQ8hpzA== ------END RSA PRIVATE KEY----- diff --git a/certdir/goodclient.pk8 b/certdir/goodclient.pk8 deleted file mode 100644 index 50af7714af6ef854ec0435bd1e676ee6c1fe30b1..0000000000000000000000000000000000000000 Binary files a/certdir/goodclient.pk8 and /dev/null differ diff --git a/certdir/goodroot.crt b/certdir/goodroot.crt deleted file mode 100644 index 09c853dbb915cd1017ebec61ca0b509f543fb1d5..0000000000000000000000000000000000000000 --- a/certdir/goodroot.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC7zCCAligAwIBAgIJAOjCfnzSGkPLMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMTExMTAyMTQz -NTdaFw0yMTExMDcyMTQzNTdaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21l -LVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApE4i3cM5 -zVAgfw8juoNN9kh/jiqZexQTUgQUrjQAMStSBVvPeoPcShbXYAZFCkICZlPdRrjY -rCyJfdFkII5W+CRh5uNPuv30NDMkCdDYvre02EsOhpmuXaJcUPL24vlTe+9+su4U -Hjy7FxOrQLe4S4kB7CNEE0lqLVDr5gXOKGkCAwEAAaOBvjCBuzAdBgNVHQ4EFgQU -0Cs8cRK/hNU0+IkSJO+rxuebtmcwgYsGA1UdIwSBgzCBgIAU0Cs8cRK/hNU0+IkS -JO+rxuebtmehXaRbMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRl -MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxv -Y2FsaG9zdIIJAOjCfnzSGkPLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -gYEATKWuep0dRQdOwO3QSOYZX3bmbgbMX5rIMn8RT3a/SX4ZD5MSZSqgVOjdmj/I -kRnlGTyexXIXgKxps4WefCuU8uFqEfGE/yKRD1Lxy4AVve9soPddKtxTAbq1TNXr -A/5bu1Qqf4tSx48qlQkWbj3Okz2yDbWEjYXWoG3ky4CCtfc= ------END CERTIFICATE----- diff --git a/certdir/server/pg_hba.conf b/certdir/server/pg_hba.conf deleted file mode 100644 index 27b76497a73a9a968249bea7b02b4cd667e7f092..0000000000000000000000000000000000000000 --- a/certdir/server/pg_hba.conf +++ /dev/null @@ -1,82 +0,0 @@ -# PostgreSQL Client Authentication Configuration File -# =================================================== -# -# Refer to the "Client Authentication" section in the -# PostgreSQL documentation for a complete description -# of this file. A short synopsis follows. -# -# This file controls: which hosts are allowed to connect, how clients -# are authenticated, which PostgreSQL user names they can use, which -# databases they can access. Records take one of these forms: -# -# local DATABASE USER METHOD [OPTIONS] -# host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS] -# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS] -# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS] -# -# (The uppercase items must be replaced by actual values.) -# -# The first field is the connection type: "local" is a Unix-domain socket, -# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an -# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket. -# -# DATABASE can be "all", "sameuser", "samerole", a database name, or -# a comma-separated list thereof. -# -# USER can be "all", a user name, a group name prefixed with "+", or -# a comma-separated list thereof. In both the DATABASE and USER fields -# you can also write a file name prefixed with "@" to include names from -# a separate file. -# -# CIDR-ADDRESS specifies the set of hosts the record matches. -# It is made up of an IP address and a CIDR mask that is an integer -# (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies -# the number of significant bits in the mask. Alternatively, you can write -# an IP address and netmask in separate columns to specify the set of hosts. -# -# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi", "krb5", -# "ident", "pam", "ldap" or "cert". Note that "password" sends passwords -# in clear text; "md5" is preferred since it sends encrypted passwords. -# -# OPTIONS are a set of options for the authentication in the format -# NAME=VALUE. The available options depend on the different authentication -# methods - refer to the "Client Authentication" section in the documentation -# for a list of which options are available for which authentication methods. -# -# Database and user names containing spaces, commas, quotes and other special -# characters must be quoted. Quoting one of the keywords "all", "sameuser" or -# "samerole" makes the name lose its special character, and just match a -# database or username with that name. -# -# This file is read on server startup and when the postmaster receives -# a SIGHUP signal. If you edit the file on a running system, you have -# to SIGHUP the postmaster for the changes to take effect. You can use -# "pg_ctl reload" to do that. - -# Put your actual configuration here -# ---------------------------------- -# -# If you want to allow non-local connections, you need to add more -# "host" records. In that case you will also need to make PostgreSQL listen -# on a non-local interface via the listen_addresses configuration parameter, -# or via the -i or -h command line switches. -# - -# CAUTION: Configuring the system for local "trust" authentication allows -# any local user to connect as any PostgreSQL user, including the database -# superuser. If you do not trust all your local users, use another -# authentication method. - - -# TYPE DATABASE USER CIDR-ADDRESS METHOD - -# "local" is for Unix domain socket connections only -local all postgres trust -# IPv4 local connections: -host all postgres 127.0.0.1/32 trust -host test all 127.0.0.1/32 md5 -host hostdb all 127.0.0.1/32 md5 -hostnossl hostnossldb all 127.0.0.1/32 md5 -hostssl hostssldb all 127.0.0.1/32 md5 clientcert=0 -hostssl hostsslcertdb all 127.0.0.1/32 md5 clientcert=1 -hostssl certdb all 127.0.0.1/32 cert diff --git a/certdir/server/root.crt b/certdir/server/root.crt deleted file mode 100644 index a45ae6c1c75d16700941c5749cb6fec7f5f24b45..0000000000000000000000000000000000000000 --- a/certdir/server/root.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3jCCAkegAwIBAgIJAM9GGWA8iSiIMA0GCSqGSIb3DQEBBQUAMFQxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3QwHhcNMTExMTEwMjE0MTQ3WhcN -MjExMTA3MjE0MTQ3WjBUMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0 -ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDEwR0 -ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCns68NbjKQAnHCpmN6amR1 -GdtliqiXDaCjoeBPpVXNQ/ZhqinP9gnDyRPXC5kPqw5/6GqNHcYJqg+IIS8G85Rq -t3Cs5ZL+JlEDAwd0CkD0Ey5h0oJNfN1bDhV2e/yqc831ElBGK6VItGqKopSUV2y/ -pNijOOdeMZ8GuktT+9mbAQIDAQABo4G3MIG0MB0GA1UdDgQWBBTE93pAIzHiFRFw -IU38WhnwXm03GzCBhAYDVR0jBH0we4AUxPd6QCMx4hURcCFN/FoZ8F5tNxuhWKRW -MFQxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAMTBHRlc3SCCQDPRhlgPIko -iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAKUsXLsp3i9Tsj1wp46R -4IkIjwWT1bN3+JOjmA9aqwEVcxTRSStAa5kfTQwc4QSAgHK1oFPsA8gsv3sftYmZ -MtvYrvba8cOPonuaCrvtJQMvKgv3d10S6esUGlW+5o3PVPUq5yQ7OaN5JHCDTZGS -phuxlq7//rNjvypX2hbKUj6z ------END CERTIFICATE----- diff --git a/certdir/server/server.crt b/certdir/server/server.crt deleted file mode 100644 index 09c853dbb915cd1017ebec61ca0b509f543fb1d5..0000000000000000000000000000000000000000 --- a/certdir/server/server.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC7zCCAligAwIBAgIJAOjCfnzSGkPLMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMTExMTAyMTQz -NTdaFw0yMTExMDcyMTQzNTdaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21l -LVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApE4i3cM5 -zVAgfw8juoNN9kh/jiqZexQTUgQUrjQAMStSBVvPeoPcShbXYAZFCkICZlPdRrjY -rCyJfdFkII5W+CRh5uNPuv30NDMkCdDYvre02EsOhpmuXaJcUPL24vlTe+9+su4U -Hjy7FxOrQLe4S4kB7CNEE0lqLVDr5gXOKGkCAwEAAaOBvjCBuzAdBgNVHQ4EFgQU -0Cs8cRK/hNU0+IkSJO+rxuebtmcwgYsGA1UdIwSBgzCBgIAU0Cs8cRK/hNU0+IkS -JO+rxuebtmehXaRbMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRl -MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxv -Y2FsaG9zdIIJAOjCfnzSGkPLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -gYEATKWuep0dRQdOwO3QSOYZX3bmbgbMX5rIMn8RT3a/SX4ZD5MSZSqgVOjdmj/I -kRnlGTyexXIXgKxps4WefCuU8uFqEfGE/yKRD1Lxy4AVve9soPddKtxTAbq1TNXr -A/5bu1Qqf4tSx48qlQkWbj3Okz2yDbWEjYXWoG3ky4CCtfc= ------END CERTIFICATE----- diff --git a/certdir/server/server.key b/certdir/server/server.key deleted file mode 100644 index f3db7c57ee99f98f8bd79148a32c5d95a96939a6..0000000000000000000000000000000000000000 --- a/certdir/server/server.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCkTiLdwznNUCB/DyO6g032SH+OKpl7FBNSBBSuNAAxK1IFW896 -g9xKFtdgBkUKQgJmU91GuNisLIl90WQgjlb4JGHm40+6/fQ0MyQJ0Ni+t7TYSw6G -ma5dolxQ8vbi+VN7736y7hQePLsXE6tAt7hLiQHsI0QTSWotUOvmBc4oaQIDAQAB -AoGAXkP1/QVkxEaUXlFxTjDHKeWuSQJnzBVYgFWXB9sNwSf5htmFz+SXHmq8Znsy -YRA+EDdNXKXwqddjiqv3pjYD7q6TgzF4D32/NwZGfF7VzBDj2fXpVxjSMZpsHixq -7GIMUTZxzqTlUMmozEFCgHycN84Pw9dmPpJ6FerqsxhPA4ECQQDQfIZuhBhBqinP -qHs1ttZQ1VIgJvCnjXXovyQF0fo53xhCqBIHAPQk/zbFDEjdH54e2gSYekBSvtwD -Dy9KmjbjAkEAyb//56WAYY3gFYBVDSyCZF5Afax0KS/eDYKlPiF45BtdxhdNTY6M -56C1+K3FiAuTMzNUbfXnDq9mZ1lZreX5QwJBAMx1gqS5WMx044Ip2YMI5s7pFRxA -8/ttiHeTk/E9RmcgubsM9nj133i07PJ7pK1uR3Q8HQunwJMlZ8B8UMWZzT8CQBD7 -zcIlZ4pO1DdbJ03FmnByksFBnEG/WtUOU3TIgpHJT/qWCZbm0ivJlqgJkOBkAQ9F -We0rzzioQVmf5vHBs1sCQDCEzTU8Ge/BrWtd1EP9JVx7aFY8c5bRvj+3FPp+43Ep -5kc1lJK8EINevxykfJ4f94S6GPLuSFfIWEys//WrH14= ------END RSA PRIVATE KEY----- diff --git a/get_PlatForm_str.sh b/get_PlatForm_str.sh deleted file mode 100644 index 3b3450c68f85fc664b90172d47d94b6bb0e1dd12..0000000000000000000000000000000000000000 --- a/get_PlatForm_str.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/bash -# ************************************************************************* -# Copyright: (c) Huawei Technologies Co., Ltd. 2019. All rights reserved -# -# description: Acording plat form, get the string info, like "redhat6.4_x86_64". -# return: $plat_form_str : we support the platform and put out $plat_form_str -# "Failed" : the plat form, not supported -# date: 2015-8-22 -# version: 1.0 -# -# ************************************************************************* -set -e - -############################################################################################## -# common paremeters: -# lsb_release and uname both suit almost all linux platform, including Redhat,CentOS,SuSE,Debian and so on. -############################################################################################## -# get os name -kernel="" -if [ -f "/etc/euleros-release" ] -then - kernel=$(cat /etc/euleros-release | awk -F ' ' '{print $1}' | tr A-Z a-z) -elif [ -f "/etc/kylin-release" ] -then - kernel=$(cat /etc/kylin-release | awk -F ' ' '{print $1}' | tr A-Z a-z) -else - kernel=$(lsb_release -d | awk -F ' ' '{print $2}'| tr A-Z a-z) -fi - -## to solve kernel="name=openeuler" -if echo $kernel | grep -q 'openeuler' -then - kernel="openeuler" -fi - -# get cpu bit -cpu_bit=$(uname -p) - -# the result info -plat_form_str="" - -################################################################################## -# redhat platform -# the result form like this: redhat6.4_x86_64 -################################################################################## -if [ "$kernel"x = "red"x ] -then - plat_form_str=redhat6.4_"$cpu_bit" -fi - -################################################################################## -# fedora platform -# the result form like this: redhat6.4_x86_64 -################################################################################## -if [ "$kernel"x = "fedora"x ] -then - plat_form_str=redhat6.4_"$cpu_bit" -fi - -################################################################################## -# suse platform -# the result form like this: suse11_sp1_x86_64 -################################################################################## -if [ "$kernel"x = "suse"x ] -then - version=$(lsb_release -r | awk -F ' ' '{print $2}') - if [ "$version"x = "12"x ] - then - plat_form_str=suse12_"$cpu_bit" - else - plat_form_str=suse11_sp1_"$cpu_bit" - fi -fi - -################################################################################## -# euler platform -# the result form like this: euleros2.0_sp8_aarch64 -################################################################################## -if [ "$kernel"x = "euleros"x ] -then - version=$(cat /etc/euleros-release | awk -F '(' '{print $2}'| awk -F ')' '{print $1}' | tr A-Z a-z) - plat_form_str=euleros2.0_"$version"_"$cpu_bit" -fi - -################################################################################## -# deepin platform -# the result form like this: deepin_aarch64 -################################################################################## -if [ "$kernel"x = "deepin"x ] -then - if [ X"$cpu_bit" = X"unknown" ] - then - cpu_bit=$(uname -m) - fi - plat_form_str=deepin15.2_"$cpu_bit" -fi -################################################################################## -# centos7.6_x86_64 platform -# centos7.5+aarch64 platform -# the result form like this: centos7.6_x86_64 or centos_7.5_aarch64 -################################################################################## -if [ "$kernel"x = "centos"x ] -then - if [ X"$cpu_bit" = X"aarch64" ] - then - plat_form_str=centos_7.5_aarch64 - else - plat_form_str=centos7.6_"$cpu_bit" - fi -fi - - -################################################################################## -# openeuler platform -# the result form like this: openeuler_aarch64 -################################################################################## -if [ "$kernel"x = "openeuler"x ] -then - plat_form_str=openeuler_"$cpu_bit" -fi - -################################################################################## -# kylin platform -# the result form like this: kylin_aarch64 -################################################################################## -if [ "$kernel"x = "kylin"x ] -then - plat_form_str=kylin_"$cpu_bit" -fi - -################################################################################## -# -# other platform -# -################################################################################## -if [ -z "$plat_form_str" ] -then - echo "Failed" -else - echo $plat_form_str -fi - diff --git a/pgjdbc/pom.xml b/pgjdbc/pom.xml index 57274a2bfb3291c8bcacc9c0c5775719f52b25d3..e2ca9a758f25ba2b6534ac3da0cf71f3f719dec0 100644 --- a/pgjdbc/pom.xml +++ b/pgjdbc/pom.xml @@ -4,7 +4,7 @@ org.opengauss opengauss-jdbc openGauss JDBC Driver - 2.0.0 + 3.0.0 Java JDBC driver for openGauss https://gitee.com/opengauss/openGauss-connector-jdbc @@ -14,7 +14,11 @@ https://jdbc.postgresql.org/about/license.html - + + org.sonatype.oss + oss-parent + 7 + openGauss https://opengauss.org/ @@ -31,17 +35,18 @@ - - com.huawei - demo-0.0.1-SNAPSHOT - 0.0.1 - junit junit 4.12 test + + org.slf4j + slf4j-api + 1.7.30 + provided + @@ -243,6 +248,33 @@ + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + + sonatype-nexus-staging + https://s01.oss.sonatype.org/ + true + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + org.apache.maven.plugins maven-site-plugin @@ -297,7 +329,7 @@ - + @@ -327,9 +359,11 @@ org.apache.maven.plugins maven-javadoc-plugin - true + false + false + maven-compiler-plugin 3.1 @@ -345,16 +379,6 @@ - - - ClouldArtifact-central - http://cmc.centralrepo.rnd.huawei.com/maven/ - - - ClouldArtifact-central - http://cmc.centralrepo.rnd.huawei.com/maven/ - - REL42.2.5 diff --git a/pgjdbc/src/main/java/org/postgresql/Driver.java b/pgjdbc/src/main/java/org/postgresql/Driver.java index 5593694d5bf3387c3de862f606730ed569b02844..63a8fa723e2b13f34ab096e87ae276ee887adcd9 100755 --- a/pgjdbc/src/main/java/org/postgresql/Driver.java +++ b/pgjdbc/src/main/java/org/postgresql/Driver.java @@ -10,8 +10,8 @@ import org.postgresql.hostchooser.MultiHostChooser; import org.postgresql.jdbc.PgConnection; import org.postgresql.log.Logger; import org.postgresql.log.Log; +import org.postgresql.log.Tracer; import org.postgresql.util.DriverInfo; -import org.postgresql.util.ExpressionProperties; import org.postgresql.util.GT; import org.postgresql.util.HostSpec; import org.postgresql.util.PSQLException; @@ -20,13 +20,8 @@ import org.postgresql.util.SharedTimer; import org.postgresql.util.URLCoder; import org.postgresql.util.WriterHandler; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; @@ -40,35 +35,14 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.Properties; import java.util.Set; +import java.util.Map; +import java.util.LinkedHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.SimpleFormatter; import java.util.logging.StreamHandler; import java.util.regex.Pattern; -import javax.net.ssl.SSLContext; - -import com.huawei.shade.org.apache.http.Header; -import com.huawei.shade.org.apache.http.HttpHeaders; -import com.huawei.shade.org.apache.http.HttpResponse; -import com.huawei.shade.org.apache.http.client.methods.HttpDelete; -import com.huawei.shade.org.apache.http.client.methods.HttpGet; -import com.huawei.shade.org.apache.http.client.methods.HttpHead; -import com.huawei.shade.org.apache.http.client.methods.HttpPatch; -import com.huawei.shade.org.apache.http.client.methods.HttpPost; -import com.huawei.shade.org.apache.http.client.methods.HttpPut; -import com.huawei.shade.org.apache.http.client.methods.HttpRequestBase; -import com.huawei.shade.org.apache.http.conn.ssl.AllowAllHostnameVerifier; -import com.huawei.shade.org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import com.huawei.shade.org.apache.http.conn.ssl.SSLContexts; -import com.huawei.shade.org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import com.huawei.shade.org.apache.http.entity.InputStreamEntity; -import com.huawei.shade.org.apache.http.impl.client.CloseableHttpClient; -import com.huawei.shade.org.apache.http.impl.client.HttpClients; -import com.huawei.shade.com.alibaba.fastjson.JSONObject; -import com.huawei.shade.com.cloud.apigateway.sdk.utils.Request; -import com.huawei.shade.com.cloud.apigateway.sdk.utils.Client; -import com.huawei.shade.com.cloud.sdk.http.HttpMethodName; /** @@ -90,105 +64,133 @@ import com.huawei.shade.com.cloud.sdk.http.HttpMethodName; */ public class Driver implements java.sql.Driver { - private static Driver registeredDriver; - private static final java.util.logging.Logger PARENT_LOGGER = java.util.logging.Logger.getLogger("org.postgresql"); - - private static Log LOGGER = Logger.getLogger("org.postgresql.Driver"); - private static SharedTimer sharedTimer = new SharedTimer(); - private static final String DEFAULT_PORT = - /*$"\""+mvn.project.property.template.default.pg.port+"\";"$*//*-*/"5431"; - private static CloseableHttpClient client = null; - private static final String gsVersion = "@GSVERSION@"; - /* generate one log file */ - public static AtomicBoolean isLogFileCreated; - static { - try { - // moved the registerDriver from the constructor to here - // because some clients call the driver themselves (I know, as - // my early jdbc work did - and that was based on other examples). - // Placing it here, means that the driver is registered once only. - register(); - } catch (SQLException e) { - throw new ExceptionInInitializerError(e); - } - } + private static Driver registeredDriver; + private static final java.util.logging.Logger PARENT_LOGGER = java.util.logging.Logger.getLogger("org.postgresql"); + + private static Log LOGGER = Logger.getLogger("org.postgresql.Driver"); + private static SharedTimer sharedTimer = new SharedTimer(); + private static final String DEFAULT_PORT = + /*$"\""+mvn.project.property.template.default.pg.port+"\";"$*//*-*/"5431"; + // Remove iam certification + // private static CloseableHttpClient client = null; + private static final String gsVersion = "@GSVERSION@"; + /* generate one log file */ + public static AtomicBoolean isLogFileCreated; + private static final String[] SENSITIVE_CHARACTERS = {"sslpassword", "iamPassword", "password"}; - // Helper to retrieve default properties from classloader resource - // properties files. - private Properties defaultProperties; + private static Tracer tracer; + private static AtomicBoolean tracerInitialized = new AtomicBoolean(false); - private synchronized Properties getDefaultProperties() throws IOException { - if (defaultProperties != null) { - return defaultProperties; + static { + try { + // moved the registerDriver from the constructor to here + // because some clients call the driver themselves (I know, as + // my early jdbc work did - and that was based on other examples). + // Placing it here, means that the driver is registered once only. + register(); + } catch (SQLException e) { + throw new ExceptionInInitializerError(e); + } } - // Make sure we load properties with the maximum possible privileges. - try { - defaultProperties = - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Properties run() throws IOException { - return loadDefaultProperties(); - } - }); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); + // Helper to retrieve default properties from classloader resource + // properties files. + private Properties defaultProperties; + + /** + * Obtain the trace id from the implementation class. + * + * @return trace id + */ + public static String getTracer() { + if (tracer == null) { + return null; + } + String traceId = tracer.getTraceId(); + if (traceId == null) { + return null; + } else if (traceId.length() > 32) { + traceId = traceId.substring(0, 32); + LOGGER.warn("When used link trace, the length of trace id should be less or equals than 32, currently " + + "truncated to " + traceId + "."); + } else if (traceId.length() < 1) { + LOGGER.warn("When used link trace, the length of trace id should be greater than 0."); + } + return traceId; } - return defaultProperties; - } + private synchronized Properties getDefaultProperties() throws IOException { + if (defaultProperties != null) { + return defaultProperties; + } - private Properties loadDefaultProperties() throws IOException { - Properties merged = new Properties(); + // Make sure we load properties with the maximum possible privileges. + try { + defaultProperties = + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Properties run() throws IOException { + return loadDefaultProperties(); + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } - try { - PGProperty.USER.set(merged, System.getProperty("user.name")); - } catch (SecurityException se) { - // We're just trying to set a default, so if we can't - // it's not a big deal. + return defaultProperties; } - // If we are loaded by the bootstrap classloader, getClassLoader() - // may return null. In that case, try to fall back to the system - // classloader. - // - // We should not need to catch SecurityException here as we are - // accessing either our own classloader, or the system classloader - // when our classloader is null. The ClassLoader javadoc claims - // neither case can throw SecurityException. - ClassLoader cl = getClass().getClassLoader(); - if (cl == null) { - LOGGER.debug("Can't find our classloader for the Driver; " - + "attempt to use the system class loader"); - cl = ClassLoader.getSystemClassLoader(); - } + private Properties loadDefaultProperties() throws IOException { + Properties merged = new Properties(); - if (cl == null) { - LOGGER.warn("Can't find a classloader for the Driver; not loading driver " - + "configuration from org/postgresql/driverconfig.properties"); - return merged; // Give up on finding defaults. - } + try { + PGProperty.USER.set(merged, System.getProperty("user.name")); + } catch (SecurityException se) { + // We're just trying to set a default, so if we can't + // it's not a big deal. + } + + // If we are loaded by the bootstrap classloader, getClassLoader() + // may return null. In that case, try to fall back to the system + // classloader. + // + // We should not need to catch SecurityException here as we are + // accessing either our own classloader, or the system classloader + // when our classloader is null. The ClassLoader javadoc claims + // neither case can throw SecurityException. + ClassLoader cl = getClass().getClassLoader(); + if (cl == null) { + LOGGER.debug("Can't find our classloader for the Driver; " + + "attempt to use the system class loader"); + cl = ClassLoader.getSystemClassLoader(); + } - LOGGER.debug("Loading driver configuration via classloader " + cl); + if (cl == null) { + LOGGER.warn("Can't find a classloader for the Driver; not loading driver " + + "configuration from org/postgresql/driverconfig.properties"); + return merged; // Give up on finding defaults. + } - // When loading the driver config files we don't want settings found - // in later files in the classpath to override settings specified in - // earlier files. To do this we've got to read the returned - // Enumeration into temporary storage. - ArrayList urls = new ArrayList(); - Enumeration urlEnum = cl.getResources("org/postgresql/driverconfig.properties"); - while (urlEnum.hasMoreElements()) { - urls.add(urlEnum.nextElement()); - } + LOGGER.debug("Loading driver configuration via classloader " + cl); - for (int i = urls.size() - 1; i >= 0; i--) { - URL url = urls.get(i); - LOGGER.debug("Loading driver configuration from: " + url); - InputStream is = url.openStream(); - merged.load(is); - is.close(); - } + // When loading the driver config files we don't want settings found + // in later files in the classpath to override settings specified in + // earlier files. To do this we've got to read the returned + // Enumeration into temporary storage. + ArrayList urls = new ArrayList(); + Enumeration urlEnum = cl.getResources("org/postgresql/driverconfig.properties"); + while (urlEnum.hasMoreElements()) { + urls.add(urlEnum.nextElement()); + } + + for (int i = urls.size() - 1; i >= 0; i--) { + URL url = urls.get(i); + LOGGER.debug("Loading driver configuration from: " + url); + InputStream is = url.openStream(); + merged.load(is); + is.close(); + } - return merged; + return merged; } public static Properties GetProps(Properties defaults, Properties info) throws PSQLException { @@ -211,878 +213,757 @@ public class Driver implements java.sql.Driver { } return newProps; } - /** - *

Try to make a database connection to the given URL. The driver should return "null" if it - * realizes it is the wrong kind of driver to connect to the given URL. This will be common, as - * when the JDBC driverManager is asked to connect to a given URL, it passes the URL to each - * loaded driver in turn.

- * - *

The driver should raise an SQLException if it is the right driver to connect to the given URL, - * but has trouble connecting to the database.

- * - *

The java.util.Properties argument can be used to pass arbitrary string tag/value pairs as - * connection arguments.

- * - *
    - *
  • user - (required) The user to connect as
  • - *
  • password - (optional) The password for the user
  • - *
  • ssl -(optional) Use SSL when connecting to the server
  • - *
  • readOnly - (optional) Set connection to read-only by default
  • - *
  • charSet - (optional) The character set to be used for converting to/from - * the database to unicode. If multibyte is enabled on the server then the character set of the - * database is used as the default, otherwise the jvm character encoding is used as the default. - * This value is only used when connecting to a 7.2 or older server.
  • - *
  • loglevel - (optional) Enable logging of messages from the driver. The value is an integer - * from 0 to 2 where: OFF = 0, INFO =1, DEBUG = 2 The output is sent to - * DriverManager.getPrintWriter() if set, otherwise it is sent to System.out.
  • - *
  • compatible - (optional) This is used to toggle between different functionality - * as it changes across different releases of the jdbc driver code. The values here are versions - * of the jdbc client and not server versions. For example in 7.1 get/setBytes worked on - * LargeObject values, in 7.2 these methods were changed to work on bytea values. This change in - * functionality could be disabled by setting the compatible level to be "7.1", in which case the - * driver will revert to the 7.1 functionality.
  • - *
- * - *

Normally, at least "user" and "password" properties should be included in the properties. For a - * list of supported character encoding , see - * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html Note that you will - * probably want to have set up the Postgres database itself to use the same encoding, with the - * {@code -E } argument to createdb.

- * - *

Our protocol takes the forms:

- * - *
-   *  jdbc:postgresql://host:port/database?param1=val1&...
-   * 
- * - * @param url the URL of the database to connect to - * @param info a list of arbitrary tag/value pairs as connection arguments - * @return a connection to the URL or null if it isnt us - * @throws SQLException if a database access error occurs - * @see java.sql.Driver#connect - */ - @Override - public Connection connect(String url, Properties info) throws SQLException { - // get defaults - Properties defaults, props; - - if (!url.startsWith("jdbc:postgresql:") && !url.startsWith("jdbc:dws:iam:")) { - return null; - } - try { - defaults = getDefaultProperties(); - } catch (IOException ioe) { - throw new PSQLException(GT.tr("Error loading default settings from driverconfig.properties"), PSQLState.UNEXPECTED_ERROR, ioe); - } - props = GetProps(defaults, info); + /** + *

Try to make a database connection to the given URL. The driver should return "null" if it + * realizes it is the wrong kind of driver to connect to the given URL. This will be common, as + * when the JDBC driverManager is asked to connect to a given URL, it passes the URL to each + * loaded driver in turn.

+ * + *

The driver should raise an SQLException if it is the right driver to connect to the given URL, + * but has trouble connecting to the database.

+ * + *

The java.util.Properties argument can be used to pass arbitrary string tag/value pairs as + * connection arguments.

+ * + *
    + *
  • user - (required) The user to connect as
  • + *
  • password - (optional) The password for the user
  • + *
  • ssl -(optional) Use SSL when connecting to the server
  • + *
  • readOnly - (optional) Set connection to read-only by default
  • + *
  • charSet - (optional) The character set to be used for converting to/from + * the database to unicode. If multibyte is enabled on the server then the character set of the + * database is used as the default, otherwise the jvm character encoding is used as the default. + * This value is only used when connecting to a 7.2 or older server.
  • + *
  • loglevel - (optional) Enable logging of messages from the driver. The value is an integer + * from 0 to 2 where: OFF = 0, INFO =1, DEBUG = 2 The output is sent to + * DriverManager.getPrintWriter() if set, otherwise it is sent to System.out.
  • + *
  • compatible - (optional) This is used to toggle between different functionality + * as it changes across different releases of the jdbc driver code. The values here are versions + * of the jdbc client and not server versions. For example in 7.1 get/setBytes worked on + * LargeObject values, in 7.2 these methods were changed to work on bytea values. This change in + * functionality could be disabled by setting the compatible level to be "7.1", in which case the + * driver will revert to the 7.1 functionality.
  • + *
+ * + *

Normally, at least "user" and "password" properties should be included in the properties. For a + * list of supported character encoding , see + * http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html Note that you will + * probably want to have set up the Postgres database itself to use the same encoding, with the + * {@code -E } argument to createdb.

+ * + *

Our protocol takes the forms:

+ * + *
+     *  jdbc:postgresql://host:port/database?param1=val1&...
+     * 
+ * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection arguments + * @return a connection to the URL or null if it isnt us + * @throws SQLException if a database access error occurs + * @see java.sql.Driver#connect + */ + @Override + public Connection connect(String url, Properties info) throws SQLException { + // get defaults + Properties defaults, props; + + String[] legalUrlTags = {"jdbc:postgresql:", "jdbc:dws:iam:"}; + boolean isUrlLegal = false; + for (String urlTag : legalUrlTags) { + if (url.startsWith(urlTag)) { + isUrlLegal = true; + } + } + if (!isUrlLegal) { + return null; + } - // parse URL and add more properties - if ((props = parseURL(url, props)) == null) { - return null; - } + try { + defaults = getDefaultProperties(); + } catch (IOException ioe) { + throw new PSQLException(GT.tr("Error loading default settings from driverconfig.properties"), + PSQLState.UNEXPECTED_ERROR, ioe); + } + props = GetProps(defaults, info); + // parse URL and add more properties + if ((props = parseURL(url, props)) == null) { + return null; + } - Logger.setLoggerName(props.getProperty("logger")); + if (!parseConnectionProperties(props)) { + return null; + } - if(Logger.isUsingJDKLogger()) { - setupLoggerFromProperties(props); - } else { - LOGGER = Logger.getLogger("org.postgresql.Driver"); - } + try { + LOGGER.debug("Connecting with URL: " + filterAuthenticationCredentials(url)); + + // Enforce login timeout, if specified, by running the connection + // attempt in a separate thread. If we hit the timeout without the + // connection completing, we abandon the connection attempt in + // the calling thread, but the separate thread will keep trying. + // Eventually, the separate thread will either fail or complete + // the connection; at that point we clean up the connection if + // we managed to establish one after all. See ConnectThread for + // more details. + long timeout = timeout(props); + if (timeout <= 0) { + Connection con = makeConnection(url, props); + return con; + } - if(PGProperty.PRIORITY_SERVERS.get(props) != null){ - if(!GlobalClusterStatusTracker.isVaildPriorityServers(props)){ - return null; - } - GlobalClusterStatusTracker.refreshProperties(props); + ConnectThread ct = new ConnectThread(url, props); + Thread thread = new Thread(ct, "PostgreSQL JDBC driver connection thread"); + thread.setDaemon(true); // Don't prevent the VM from shutting down + thread.start(); + return ct.getResult(timeout); + } catch (PSQLException ex1) { + LOGGER.debug("Connection error: ", ex1); + // re-throw the exception, otherwise it will be caught next, and a + // org.postgresql.unusual error will be returned instead. + throw ex1; + } catch (java.security.AccessControlException ace) { + throw new PSQLException(GT.tr("Your security policy has prevented the connection from being attempted. " + + "You probably need to grant the connect java.net.SocketPermission to the database server host and" + + " port that you wish to connect to."), PSQLState.UNEXPECTED_ERROR, ace); + } catch (Exception ex2) { + LOGGER.debug("Unexpected connection error: ", ex2); + throw new PSQLException(GT.tr("Something unusual has occured to cause the driver to fail. Please report " + + "this exception."), PSQLState.UNEXPECTED_ERROR, ex2); + } } - if (MultiHostChooser.isUsingAutoLoadBalance(props)) { - if(!MultiHostChooser.isVaildPriorityLoadBalance(props)){ - return null; - } - QueryCNListUtils.refreshProperties(props); - } + /** + * Parse the configuration items in the connection string. + * + * @param props Connection Properties + */ + private Boolean parseConnectionProperties(Properties props) { + Logger.setLoggerName(props.getProperty("logger")); + if (Logger.isUsingJDKLogger()) { + setupLoggerFromProperties(props); + } else { + LOGGER = Logger.getLogger("org.postgresql.Driver"); + } - try { - LOGGER.debug("Connecting with URL: " + url); - - // Enforce login timeout, if specified, by running the connection - // attempt in a separate thread. If we hit the timeout without the - // connection completing, we abandon the connection attempt in - // the calling thread, but the separate thread will keep trying. - // Eventually, the separate thread will either fail or complete - // the connection; at that point we clean up the connection if - // we managed to establish one after all. See ConnectThread for - // more details. - long timeout = timeout(props); - if (timeout <= 0) { - Connection con = makeConnection(url, props); - return con; - } - - ConnectThread ct = new ConnectThread(url, props); - Thread thread = new Thread(ct, "PostgreSQL JDBC driver connection thread"); - thread.setDaemon(true); // Don't prevent the VM from shutting down - thread.start(); - return ct.getResult(timeout); - } catch (PSQLException ex1) { - LOGGER.debug("Connection error: ",ex1); - // re-throw the exception, otherwise it will be caught next, and a - // org.postgresql.unusual error will be returned instead. - throw ex1; - } catch (java.security.AccessControlException ace) { - throw new PSQLException(GT.tr("Your security policy has prevented the connection from being attempted. You probably need to grant the connect java.net.SocketPermission to the database server host and port that you wish to connect to."), PSQLState.UNEXPECTED_ERROR, ace); - } catch (Exception ex2) { - LOGGER.debug("Unexpected connection error: ", ex2); - throw new PSQLException(GT.tr("Something unusual has occured to cause the driver to fail. Please report this exception."), PSQLState.UNEXPECTED_ERROR, ex2); + Boolean parseStatus = true; + if (PGProperty.PRIORITY_SERVERS.get(props) != null) { + if (!GlobalClusterStatusTracker.isVaildPriorityServers(props)) { + parseStatus = false; + } + GlobalClusterStatusTracker.refreshProperties(props); + } + + if (MultiHostChooser.isUsingAutoLoadBalance(props)) { + if (!MultiHostChooser.isVaildPriorityLoadBalance(props)) { + parseStatus = false; + } + QueryCNListUtils.refreshProperties(props); + } + return parseStatus; } - } - - // Used to check if the handler file is the same - private static String loggerHandlerFile; - - /** - *

Setup java.util.logging.Logger using connection properties.

- * - *

See {@link PGProperty#LOGGER_FILE} and {@link PGProperty#LOGGER_FILE}

- * - * @param props Connection Properties - */ - private Boolean initLoggerProperties(String driverLogLevel) { - if (driverLogLevel == null) { - return false; // Don't mess with Logger if not set + + // Used to check if the handler file is the same + private static String loggerHandlerFile; + + /** + *

Setup java.util.logging.Logger using connection properties.

+ * + *

See {@link PGProperty#LOGGER_FILE} and {@link PGProperty#LOGGER_FILE}

+ * + * @param driverLogLevel Connection Properties + */ + private Boolean initLoggerProperties(String driverLogLevel) { + if (driverLogLevel == null) { + return false; // Don't mess with Logger if not set } if (!"OFF".equalsIgnoreCase(driverLogLevel) && !isLogFileCreated.compareAndSet(false, true)) { return false; } if ("OFF".equalsIgnoreCase(driverLogLevel)) { - PARENT_LOGGER.setLevel(Level.OFF); - return false; // Don't mess with Logger if set to OFF + PARENT_LOGGER.setLevel(Level.OFF); + return false; // Don't mess with Logger if set to OFF } else if ("DEBUG".equalsIgnoreCase(driverLogLevel)) { - PARENT_LOGGER.setLevel(Level.FINE); + PARENT_LOGGER.setLevel(Level.FINE); } else if ("TRACE".equalsIgnoreCase(driverLogLevel)) { - PARENT_LOGGER.setLevel(Level.FINEST); + PARENT_LOGGER.setLevel(Level.FINEST); } else if ("INFO".equalsIgnoreCase(driverLogLevel)) { PARENT_LOGGER.setLevel(Level.INFO); } else { - PARENT_LOGGER.setLevel(Level.OFF); + PARENT_LOGGER.setLevel(Level.OFF); } return true; - } - /** - *

Setup java.util.logging.Logger using connection properties.

- * - *

See {@link PGProperty#LOGGER_FILE} and {@link PGProperty#LOGGER_FILE}

- * - * @param props Connection Properties - */ - private void setupLoggerFromProperties(final Properties props) { - final String driverLogLevel = PGProperty.LOGGER_LEVEL.get(props); - if (!initLoggerProperties(driverLogLevel)) { - return; } - ExpressionProperties exprProps = new ExpressionProperties(props, System.getProperties()); - final String driverLogFile = PGProperty.LOGGER_FILE.get(exprProps); - if (driverLogFile != null && driverLogFile.equals(loggerHandlerFile)) { - return; // Same file output, do nothing. - } + /** + *

Setup java.util.logging.Logger using connection properties.

+ * + *

See {@link PGProperty#LOGGER_FILE} and {@link PGProperty#LOGGER_FILE}

+ * + * @param props Connection Properties + */ + private void setupLoggerFromProperties(final Properties props) { + final String driverLogLevel = PGProperty.LOGGER_LEVEL.get(props); + if (!initLoggerProperties(driverLogLevel)) { + return; + } - for (java.util.logging.Handler handlers : PARENT_LOGGER.getHandlers()) { - // Remove previously set Handlers - handlers.close(); - PARENT_LOGGER.removeHandler(handlers); - loggerHandlerFile = null; - } + final String driverLogFile = PGProperty.LOGGER_FILE.getDefaultValue(); + if (driverLogFile != null && driverLogFile.equals(loggerHandlerFile)) { + return; // Same file output, do nothing. + } - java.util.logging.Handler handler = null; - if (driverLogFile != null) { - try { - handler = new java.util.logging.FileHandler(driverLogFile); - loggerHandlerFile = driverLogFile; - } catch (Exception ex) { - System.err.println("Cannot enable FileHandler, fallback to ConsoleHandler."); - } - } + for (java.util.logging.Handler handlers : PARENT_LOGGER.getHandlers()) { + // Remove previously set Handlers + handlers.close(); + PARENT_LOGGER.removeHandler(handlers); + loggerHandlerFile = null; + } - Formatter formatter = new SimpleFormatter(); - - if ( handler == null ) { - if (DriverManager.getLogWriter() != null) { - handler = new WriterHandler(DriverManager.getLogWriter()); - } else if ( DriverManager.getLogStream() != null) { - handler = new StreamHandler(DriverManager.getLogStream(), formatter); - } else { - handler = new StreamHandler(System.err, formatter); - } - } else { - handler.setFormatter(formatter); - } + java.util.logging.Handler handler = null; + if (driverLogFile != null) { + try { + handler = new java.util.logging.FileHandler(driverLogFile); + loggerHandlerFile = driverLogFile; + } catch (Exception ex) { + System.err.println("Cannot enable FileHandler, fallback to ConsoleHandler."); + } + } + + Formatter formatter = new SimpleFormatter(); + + if (handler == null) { + if (DriverManager.getLogWriter() != null) { + handler = new WriterHandler(DriverManager.getLogWriter()); + } else if (DriverManager.getLogStream() != null) { + handler = new StreamHandler(DriverManager.getLogStream(), formatter); + } else { + handler = new StreamHandler(System.err, formatter); + } + } else { + handler.setFormatter(formatter); + } - handler.setLevel(PARENT_LOGGER.getLevel()); - PARENT_LOGGER.setUseParentHandlers(false); - PARENT_LOGGER.addHandler(handler); - } - - /** - * Perform a connect in a separate thread; supports getting the results from the original thread - * while enforcing a login timeout. - */ - private static class ConnectThread implements Runnable { - ConnectThread(String url, Properties props) { - this.url = url; - this.props = props; + handler.setLevel(PARENT_LOGGER.getLevel()); + PARENT_LOGGER.setUseParentHandlers(false); + PARENT_LOGGER.addHandler(handler); } - public void run() { - Connection conn; - Throwable error; - - try { - conn = makeConnection(url, props); - error = null; - } catch (Throwable t) { - conn = null; - error = t; - } - - synchronized (this) { - if (abandoned) { - if (conn != null) { + /** + * Perform a connect in a separate thread; supports getting the results from the original thread + * while enforcing a login timeout. + */ + private static class ConnectThread implements Runnable { + ConnectThread(String url, Properties props) { + this.url = url; + this.props = props; + } + + public void run() { + Connection conn; + Throwable error; + try { - conn.close(); - } catch (SQLException e) { + conn = makeConnection(url, props); + error = null; + } catch (Throwable t) { + conn = null; + error = t; + } + + synchronized (this) { + if (abandoned) { + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + } + } + } else { + result = conn; + resultException = error; + notify(); + } } - } - } else { - result = conn; - resultException = error; - notify(); } - } + + /** + * Get the connection result from this (assumed running) thread. If the timeout is reached + * without a result being available, a SQLException is thrown. + * + * @param timeout timeout in milliseconds + * @return the new connection, if successful + * @throws SQLException if a connection error occurs or the timeout is reached + */ + public Connection getResult(long timeout) throws SQLException { + long expiry = System.currentTimeMillis() + timeout; + synchronized (this) { + while (true) { + if (result != null) { + return result; + } + + if (resultException != null) { + if (resultException instanceof SQLException) { + resultException.fillInStackTrace(); + throw (SQLException) resultException; + } else { + throw new PSQLException( + GT.tr( + "Something unusual has occured to cause the driver to fail. Please report" + + " this exception."), + PSQLState.UNEXPECTED_ERROR, resultException); + } + } + + long delay = expiry - System.currentTimeMillis(); + if (delay <= 0) { + abandoned = true; + throw new PSQLException(GT.tr("Connection attempt timed out."), + PSQLState.CONNECTION_UNABLE_TO_CONNECT); + } + + try { + wait(delay); + } catch (InterruptedException ie) { + + // reset the interrupt flag + Thread.currentThread().interrupt(); + abandoned = true; + + // throw an unchecked exception which will hopefully not be ignored by the calling code + throw new RuntimeException(GT.tr("Interrupted while attempting to connect.")); + } + } + } + } + + private final String url; + private final Properties props; + private Connection result; + private Throwable resultException; + private boolean abandoned; } /** - * Get the connection result from this (assumed running) thread. If the timeout is reached - * without a result being available, a SQLException is thrown. + * Create a connection from URL and properties. Always does the connection work in the current + * thread without enforcing a timeout, regardless of any timeout specified in the properties. * - * @param timeout timeout in milliseconds - * @return the new connection, if successful - * @throws SQLException if a connection error occurs or the timeout is reached + * @param url the original URL + * @param props the parsed/defaulted connection properties + * @return a new connection + * @throws SQLException if the connection could not be made */ - public Connection getResult(long timeout) throws SQLException { - long expiry = System.currentTimeMillis() + timeout; - synchronized (this) { - while (true) { - if (result != null) { - return result; - } - - if (resultException != null) { - if (resultException instanceof SQLException) { - resultException.fillInStackTrace(); - throw (SQLException) resultException; - } else { - throw new PSQLException( - GT.tr( - "Something unusual has occured to cause the driver to fail. Please report this exception."), - PSQLState.UNEXPECTED_ERROR, resultException); - } - } - - long delay = expiry - System.currentTimeMillis(); - if (delay <= 0) { - abandoned = true; - throw new PSQLException(GT.tr("Connection attempt timed out."), - PSQLState.CONNECTION_UNABLE_TO_CONNECT); - } - - try { - wait(delay); - } catch (InterruptedException ie) { - - // reset the interrupt flag - Thread.currentThread().interrupt(); - abandoned = true; - - // throw an unchecked exception which will hopefully not be ignored by the calling code - throw new RuntimeException(GT.tr("Interrupted while attempting to connect.")); - } + private static Connection makeConnection(String url, Properties props) throws SQLException { + PgConnection pgConnection = new PgConnection(hostSpecs(props), user(props), database(props), props, url); + GlobalConnectionTracker.possessConnectionReference(pgConnection.getQueryExecutor(), props); + return pgConnection; + } + + /** + * Returns true if the driver thinks it can open a connection to the given URL. Typically, drivers + * will return true if they understand the subprotocol specified in the URL and false if they + * don't. Our protocols start with jdbc:postgresql: + * + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @throws PSQLException + * @see java.sql.Driver#acceptsURL + */ + @Override + public boolean acceptsURL(String url) throws PSQLException { + return parseURL(url, null) != null; + } + + /** + *

The getPropertyInfo method is intended to allow a generic GUI tool to discover what properties + * it should prompt a human for in order to get enough information to connect to a database.

+ * + *

Note that depending on the values the human has supplied so far, additional values may become + * necessary, so it may be necessary to iterate through several calls to getPropertyInfo

+ * + * @param url the Url of the database to connect to + * @param info a proposed list of tag/value pairs that will be sent on connect open. + * @return An array of DriverPropertyInfo objects describing possible properties. This array may + * be an empty array if no properties are required + * @throws PSQLException + * @see java.sql.Driver#getPropertyInfo + */ + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws PSQLException { + Properties copy = new Properties(info); + Properties parse = parseURL(url, copy); + if (parse != null) { + copy = parse; + } + + PGProperty[] knownProperties = PGProperty.values(); + DriverPropertyInfo[] props = new DriverPropertyInfo[knownProperties.length]; + for (int i = 0; i < props.length; ++i) { + props[i] = knownProperties[i].toDriverPropertyInfo(copy); } - } + + return props; + } + + @Override + public int getMajorVersion() { + return org.postgresql.util.DriverInfo.MAJOR_VERSION; } - private final String url; - private final Properties props; - private Connection result; - private Throwable resultException; - private boolean abandoned; - } - - /** - * Create a connection from URL and properties. Always does the connection work in the current - * thread without enforcing a timeout, regardless of any timeout specified in the properties. - * - * @param url the original URL - * @param props the parsed/defaulted connection properties - * @return a new connection - * @throws SQLException if the connection could not be made - */ - private static Connection makeConnection(String url, Properties props) throws SQLException { - PgConnection pgConnection = new PgConnection(hostSpecs(props), user(props), database(props), props, url); - GlobalConnectionTracker.possessConnectionReference(pgConnection.getQueryExecutor(), props); - return pgConnection; - } - - /** - * Returns true if the driver thinks it can open a connection to the given URL. Typically, drivers - * will return true if they understand the subprotocol specified in the URL and false if they - * don't. Our protocols start with jdbc:postgresql: - * - * @param url the URL of the driver - * @return true if this driver accepts the given URL - * @throws PSQLException - * @see java.sql.Driver#acceptsURL - */ - @Override - public boolean acceptsURL(String url) throws PSQLException { - return parseURL(url, null) != null; - } - - /** - *

The getPropertyInfo method is intended to allow a generic GUI tool to discover what properties - * it should prompt a human for in order to get enough information to connect to a database.

- * - *

Note that depending on the values the human has supplied so far, additional values may become - * necessary, so it may be necessary to iterate through several calls to getPropertyInfo

- * - * @param url the Url of the database to connect to - * @param info a proposed list of tag/value pairs that will be sent on connect open. - * @return An array of DriverPropertyInfo objects describing possible properties. This array may - * be an empty array if no properties are required - * @throws PSQLException - * @see java.sql.Driver#getPropertyInfo - */ - @Override - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws PSQLException { - Properties copy = new Properties(info); - Properties parse = parseURL(url, copy); - if (parse != null) { - copy = parse; + @Override + public int getMinorVersion() { + return org.postgresql.util.DriverInfo.MINOR_VERSION; } - PGProperty[] knownProperties = PGProperty.values(); - DriverPropertyInfo[] props = new DriverPropertyInfo[knownProperties.length]; - for (int i = 0; i < props.length; ++i) { - props[i] = knownProperties[i].toDriverPropertyInfo(copy); + /** + * Returns the server version series of this driver and the specific build number. + * + * @return JDBC driver version + * @deprecated use {@link #getMajorVersion()} and {@link #getMinorVersion()} instead + */ + @Deprecated + public static String getVersion() { + return DriverInfo.DRIVER_FULL_NAME; } - return props; - } - - @Override - public int getMajorVersion() { - return org.postgresql.util.DriverInfo.MAJOR_VERSION; - } - - @Override - public int getMinorVersion() { - return org.postgresql.util.DriverInfo.MINOR_VERSION; - } - - /** - * Returns the server version series of this driver and the specific build number. - * - * @return JDBC driver version - * @deprecated use {@link #getMajorVersion()} and {@link #getMinorVersion()} instead - */ - @Deprecated - public static String getVersion() { - return DriverInfo.DRIVER_FULL_NAME; - } - - /** - *

Report whether the driver is a genuine JDBC compliant driver. A driver may only report "true" - * here if it passes the JDBC compliance tests, otherwise it is required to return false. JDBC - * compliance requires full support for the JDBC API and full support for SQL 92 Entry Level.

- * - *

For PostgreSQL, this is not yet possible, as we are not SQL92 compliant (yet).

- */ - @Override - public boolean jdbcCompliant() { - return false; - } - - public static String parseIPValid(String address) { - if (address == "" || address == null) { - return address; - } - String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." - + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." - + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." - + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"; - Pattern pattern = Pattern.compile(regex); - if (!pattern.matcher(address).matches()) { - LOGGER.debug("JDBC URL invalid ip address: " + address); - } - return address; - } - - /** - * Constructs a new DriverURL, splitting the specified URL into its component parts. - * - * @param url JDBC URL to parse - * @param defaults Default properties - * @return Properties with elements added from the url - * @throws PSQLException - */ - public static Properties parseURL(String url, Properties defaults) throws PSQLException { - Properties urlProps = new Properties(defaults); - String l_urlServer = url; - String l_urlArgs = ""; - - int l_qPos = url.indexOf('?'); - if (l_qPos != -1) { - l_urlServer = url.substring(0, l_qPos); - l_urlArgs = url.substring(l_qPos + 1); + /** + *

Report whether the driver is a genuine JDBC compliant driver. A driver may only report "true" + * here if it passes the JDBC compliance tests, otherwise it is required to return false. JDBC + * compliance requires full support for the JDBC API and full support for SQL 92 Entry Level.

+ * + *

For PostgreSQL, this is not yet possible, as we are not SQL92 compliant (yet).

+ */ + @Override + public boolean jdbcCompliant() { + return false; } - if (!l_urlServer.startsWith("jdbc:postgresql:") && !l_urlServer.startsWith("jdbc:dws:iam:")) { - LOGGER.debug("JDBC URL must start with \"jdbc:postgresql:\" or \"jdbc:dws:iam:\" but was: " + url); - return null; + public static String parseIPValid(String address) { + if (address == "" || address == null) { + return address; + } + String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." + + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"; + Pattern pattern = Pattern.compile(regex); + if (!pattern.matcher(address).matches()) { + LOGGER.debug("JDBC URL invalid ip address: " + address); + } + return address; } - if(l_urlServer.startsWith("jdbc:postgresql:")) { - l_urlServer = l_urlServer.substring("jdbc:postgresql:".length()); - - if (l_urlServer.startsWith("//")) { - l_urlServer = l_urlServer.substring(2); - int slash = l_urlServer.indexOf('/'); - if (slash == -1) { - LOGGER.warn("JDBC URL must contain a / at the end of the host or port: " + url); - return null; + + /** + * Constructs a new DriverURL, splitting the specified URL into its component parts. + * + * @param url JDBC URL to parse + * @param defaults Default properties + * @return Properties with elements added from the url + * @throws PSQLException + */ + public static Properties parseURL(String url, Properties defaults) throws PSQLException { + Properties urlProps = new Properties(defaults); + String l_urlServer = url; + String l_urlArgs = ""; + boolean isUrlLegal = false; + String[] legalUrlTags = {"jdbc:postgresql:", "jdbc:dws:iam:"}; + + int l_qPos = url.indexOf('?'); + if (l_qPos != -1) { + l_urlServer = url.substring(0, l_qPos); + l_urlArgs = url.substring(l_qPos + 1); + } + + for (String urlTag : legalUrlTags) { + if (l_urlServer.startsWith(urlTag)) { + isUrlLegal = true; } - urlProps.setProperty("PGDBNAME", URLCoder.decode(l_urlServer.substring(slash + 1))); - - // Save the ip and port configured in the url - String[] addresses = l_urlServer.substring(0, slash).split(","); - StringBuilder hosts = new StringBuilder(); - StringBuilder ports = new StringBuilder(); - for (String address : addresses) { - int portIdx = address.lastIndexOf(':'); - if (portIdx != -1 && address.lastIndexOf(']') < portIdx) { - String portStr = address.substring(portIdx + 1); - try { - int port = Integer.parseInt(portStr); - if (port < 1 || port > 65535) { - LOGGER.warn("JDBC URL port: " + portStr + " not valid (1:65535) "); + } + + if (!isUrlLegal) { + LOGGER.debug("JDBC URL must start with \"jdbc:postgresql:\" or \"jdbc:dws:iam:\" but was: " + + filterAuthenticationCredentials(url)); + return null; + } + + //if (l_urlServer.startsWith("jdbc:postgresql:")) { + l_urlServer = l_urlServer.substring("jdbc:postgresql:".length()); + + if (l_urlServer.startsWith("//")) { + l_urlServer = l_urlServer.substring(2); + int slash = l_urlServer.indexOf('/'); + if (slash == -1) { + LOGGER.warn("JDBC URL must contain a / at the end of the host or port: " + + filterAuthenticationCredentials(url)); + return null; + } + urlProps.setProperty("PGDBNAME", URLCoder.decode(l_urlServer.substring(slash + 1))); + + // Save the ip and port configured in the url + String[] addresses = l_urlServer.substring(0, slash).split(","); + StringBuilder hosts = new StringBuilder(); + StringBuilder ports = new StringBuilder(); + for (String address : addresses) { + int portIdx = address.lastIndexOf(':'); + if (portIdx != -1 && address.lastIndexOf(']') < portIdx) { + String portStr = address.substring(portIdx + 1); + try { + int port = Integer.parseInt(portStr); + if (port < 1 || port > 65535) { + LOGGER.warn("JDBC URL port: " + portStr + " not valid (1:65535) "); + return null; + } + } catch (NumberFormatException ignore) { + LOGGER.warn("JDBC URL invalid port number: " + portStr); return null; } - } catch (NumberFormatException ignore) { - LOGGER.warn("JDBC URL invalid port number: " + portStr); - return null; + ports.append(portStr); + hosts.append(parseIPValid((String) address.subSequence(0, portIdx))); + } else { + ports.append(DEFAULT_PORT); + hosts.append(parseIPValid(address)); } - ports.append(portStr); - hosts.append(parseIPValid((String) address.subSequence(0, portIdx))); - } else { - ports.append(DEFAULT_PORT); - hosts.append(parseIPValid(address)); + ports.append(','); + hosts.append(','); } - ports.append(','); - hosts.append(','); - } - ports.setLength(ports.length() - 1); - hosts.setLength(hosts.length() - 1); + ports.setLength(ports.length() - 1); + hosts.setLength(hosts.length() - 1); - urlProps.setProperty("PGHOST", hosts.toString()); - urlProps.setProperty("PGPORT", ports.toString()); + urlProps.setProperty("PGHOST", hosts.toString()); + urlProps.setProperty("PGPORT", ports.toString()); - //The first connection, put the host and port in the url into the props - urlProps.setProperty("PGHOSTURL", hosts.toString()); - urlProps.setProperty("PGPORTURL", ports.toString()); - } else { + //The first connection, put the host and port in the url into the props + urlProps.setProperty("PGHOSTURL", hosts.toString()); + urlProps.setProperty("PGPORTURL", ports.toString()); + } else { /* if there are no defaults set or any one of PORT, HOST, DBNAME not set then set it to default */ - if (defaults == null || !defaults.containsKey("PGPORT")) { - urlProps.setProperty("PGPORT", DEFAULT_PORT); + if (defaults == null || !defaults.containsKey("PGPORT")) { + urlProps.setProperty("PGPORT", DEFAULT_PORT); + } + if (defaults == null || !defaults.containsKey("PGHOST")) { + urlProps.setProperty("PGHOST", "localhost"); + } + if (defaults == null || !defaults.containsKey("PGDBNAME")) { + urlProps.setProperty("PGDBNAME", URLCoder.decode(l_urlServer)); + } + } + + // parse the args part of the url + urlProps.putAll(praseParam(l_urlArgs)); + if (urlProps.getProperty("enable_ce") != null && urlProps.getProperty("enable_ce").equals("1")) { + urlProps.setProperty("CLIENTLOGIC", "1"); } - if (defaults == null || !defaults.containsKey("PGHOST")) { - urlProps.setProperty("PGHOST", "localhost"); + return urlProps; + } + + /** + * Shield sensitive information in the connection string, such as password, sslpassword, iamPassword + * + * @param url Connection string. + * @return Connection string without sensitive information + */ + private static String filterAuthenticationCredentials(String url) { + String notSensitiveUrl = url; + int paramStartIndex = notSensitiveUrl.indexOf("?"); + if (paramStartIndex != -1) { + LinkedHashMap paramsMap = praseParam(notSensitiveUrl.substring(paramStartIndex + 1)); + StringBuilder stringBuilder = new StringBuilder(notSensitiveUrl.substring(0, paramStartIndex) + "?"); + for (Map.Entry entry : paramsMap.entrySet()) { + boolean isKeyword = false; + for (String sensitiveCharacter : SENSITIVE_CHARACTERS) { + if (entry.getKey().equals(sensitiveCharacter)) { + isKeyword = true; + break; + } + } + if (!isKeyword) { + stringBuilder.append(entry.getKey() + "=" + entry.getValue() + "&"); + } } - if (defaults == null || !defaults.containsKey("PGDBNAME")) { - urlProps.setProperty("PGDBNAME", URLCoder.decode(l_urlServer)); + notSensitiveUrl = stringBuilder.toString(); + if (notSensitiveUrl.endsWith("?") || notSensitiveUrl.endsWith("&")) { + notSensitiveUrl = notSensitiveUrl.substring(0, notSensitiveUrl.length() - 1); } } + return notSensitiveUrl; + } - // parse the args part of the url - String[] args = l_urlArgs.split("&"); + /** + * @param urlArgs The parameter part in the connection string + * @return parameter map + */ + private static LinkedHashMap praseParam(String urlArgs) { + LinkedHashMap paramsMap = new LinkedHashMap<>(); + String[] args = urlArgs.split("&"); for (String token : args) { if (token.isEmpty()) { continue; } int l_pos = token.indexOf('='); if (l_pos == -1) { - urlProps.setProperty(token, ""); + paramsMap.put(token, ""); } else { - urlProps.setProperty(token.substring(0, l_pos), URLCoder.decode(token.substring(l_pos + 1))); + paramsMap.put(token.substring(0, l_pos), URLCoder.decode(token.substring(l_pos + 1))); } } - if(urlProps.getProperty("enable_ce") != null && urlProps.getProperty("enable_ce").equals("1")) { - urlProps.setProperty("CLIENTLOGIC", "1"); - } - return urlProps; - }else { - StringBuffer tmp = new StringBuffer(); - l_urlServer = l_urlServer.substring("jdbc:dws:iam:".length()); - String ClusterIdentifier="", region="", DbUser="", AutoCreate="", AccessKeyID="", SecretAccessKey=""; - if (l_urlServer.startsWith("//")) { - l_urlServer = l_urlServer.substring(2); - int slash = l_urlServer.indexOf('/'); - if (slash == -1) { - return null; - } - urlProps.setProperty("PGDBNAME", l_urlServer.substring(slash + 1)); - - String serverurl = l_urlServer.substring(0, slash); - String[] clusterurl = serverurl.split(":"); - if(clusterurl.length != 2){ - return null; - } - ClusterIdentifier = clusterurl[0]; - region = clusterurl[1]; + return paramsMap; + } + /* public method */ + public static HostSpec[] GetHostSpecs(Properties props) { + return hostSpecs(props); + } + + /** + * @param props Connection properties + * @return the address portion of the orgin URL + */ + public static HostSpec[] getURLHostSpecs(Properties props) { + return urlHostSpecs(props); + } + + public static String GetUser(Properties props) { + return user(props); + } + + public static String GetDatabase(Properties props) { + return database(props); + } + + private static HostSpec[] urlHostSpecs(Properties props) { + String[] ports = props.getProperty("PGPORTURL").split(","); + String[] hosts = props.getProperty("PGHOSTURL").split(",", ports.length); + HostSpec[] hostSpecs = new HostSpec[hosts.length]; + for (int i = 0; i < hostSpecs.length; ++i) { + hostSpecs[i] = new HostSpec(hosts[i], Integer.parseInt(ports[i])); } - - //parse the args part of the url - String[] args = l_urlArgs.split("&"); - for (int i = 0; i < args.length; ++i) - { - String token = args[i]; - if (token.length() == 0) { - continue; - } - int l_pos = token.indexOf('='); - if (l_pos == -1) - { - urlProps.setProperty(token, ""); - } - else - { - if(token.substring(0, l_pos).equals("AccessKeyID")){ - AccessKeyID = token.substring(l_pos + 1); - }else if(token.substring(0, l_pos).equals("SecretAccessKey")){ - SecretAccessKey = token.substring(l_pos + 1); - }else if(token.substring(0, l_pos).equals("DbUser")){ - DbUser = token.substring(l_pos + 1); - }else if(token.substring(0, l_pos).equals("AutoCreate")){ - AutoCreate = token.substring(l_pos + 1); - }else{ - tmp.append("&"+token.substring(0, l_pos)+"="+token.substring(l_pos + 1)); - } - } - } - StringBuffer jdbcUrl = new StringBuffer(); - if(region.equals("") || ClusterIdentifier.equals("") || DbUser.equals("") || AccessKeyID.equals("") - || SecretAccessKey.equals("")){ - throw new PSQLException(GT.tr("Please confirm that all the parameters needed is added to the url."), PSQLState.CONNECTION_REJECTED); - } - InputStream in = null; - Properties props = new Properties(); - String domainName = ""; - try { - File f = new File(Driver.class.getClassLoader().getResource("").getPath()); - String filePath = f.getParent() + File.separator + "config" + File.separator + "jdbcconfig.properties"; - in = new BufferedInputStream(new FileInputStream(filePath)); - props = new Properties(); - props.load(in); - domainName = props.getProperty(region); - in.close(); - } catch (Exception e) { - if (in != null) { - try { - in.close(); - } catch (IOException ioe) { - LOGGER.warn(ioe.getMessage()); - } - } - try { - props = new Properties(); - in = Driver.class.getResourceAsStream("/org/postgresql/jdbcconfig.properties"); - props.load(in); - domainName = props.getProperty(region); - in.close(); - } catch (Exception e1) { - if (in != null) { - try { - in.close(); - } catch (IOException ioe) { - LOGGER.warn(ioe.getMessage()); - } - } - throw new PSQLException(GT.tr("Parse jdbcconfig.properties failed."), - PSQLState.CONNECTION_UNABLE_TO_CONNECT, e1); - } - } - if(domainName == null || domainName.equals("")) { - throw new PSQLException(GT.tr("Unrecognized region name."), PSQLState.CONNECTION_REJECTED); - } - jdbcUrl.append("https://" + domainName + "/credentials?"); - jdbcUrl.append("clusterName="+ClusterIdentifier); - jdbcUrl.append("&dbUser="+DbUser); - if(!AutoCreate.equals("")) { - jdbcUrl.append("&autoCreate="+AutoCreate); + return hostSpecs; + } + + /** + * @return the address portion of the URL + */ + private static HostSpec[] hostSpecs(Properties props) { + String[] ports = props.getProperty("PGPORT").split(","); + String[] hosts = props.getProperty("PGHOST").split(",", ports.length); + HostSpec[] hostSpecs = new HostSpec[hosts.length]; + for (int i = 0; i < hostSpecs.length; ++i) { + hostSpecs[i] = new HostSpec(hosts[i], Integer.parseInt(ports[i])); } - jdbcUrl.append(tmp.toString()); + return hostSpecs; + } - String jsonstr=""; - jsonstr = getReturn(AccessKeyID, SecretAccessKey, jdbcUrl.toString(), region); - try { - JSONObject jsonObj = JSONObject.parseObject(jsonstr); - if(jsonObj.get("cluster_credentials") != null){ - jsonstr = jsonObj.get("cluster_credentials").toString(); - jsonObj = JSONObject.parseObject(jsonstr); - if(jsonObj.get("db_user")!=null){ - urlProps.setProperty("user", jsonObj.get("db_user").toString()); - } - if(jsonObj.get("db_endpoint")!=null){ - urlProps.setProperty("PGHOST", jsonObj.get("db_endpoint").toString()); - } - if(jsonObj.get("db_port")!=null){ - urlProps.setProperty("PGPORT", jsonObj.get("db_port").toString()); - } - if(jsonObj.get("db_password")!=null){ - urlProps.setProperty("password", jsonObj.get("db_password").toString()); - } + /** + * @return the username of the URL + */ + private static String user(Properties props) { + return props.getProperty("user", ""); + } - //The first connection, put the host and port in the url into the clusters - urlProps.setProperty("PGHOSTURL", urlProps.getProperty("PGHOST")); - urlProps.setProperty("PGPORTURL", urlProps.getProperty("PGPORT")); - } else if(jsonObj.get("externalMessage") != null) { - throw new PSQLException (GT.tr(jsonObj.get("externalMessage").toString()), PSQLState.CONNECTION_UNABLE_TO_CONNECT); - } else { - throw new PSQLException (GT.tr("The format of Token is not as expected."), PSQLState.CONNECTION_UNABLE_TO_CONNECT); + /** + * @return the database name of the URL + */ + private static String database(Properties props) { + return props.getProperty("PGDBNAME", ""); + } + + /** + * @return the timeout from the URL, in milliseconds + */ + private static long timeout(Properties props) { + String timeout = PGProperty.LOGIN_TIMEOUT.get(props); + if (timeout != null) { + try { + return (long) (Float.parseFloat(timeout) * 1000); + } catch (NumberFormatException e) { + LOGGER.warn("Couldn't parse loginTimeout value: " + timeout); } - } catch (Exception e) { - throw new PSQLException (GT.tr("Parse the token failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT, e); - } - if(urlProps.getProperty("ssl") == null && urlProps.getProperty("sslmode") == null) { - urlProps.setProperty("sslmode", "require"); - } - if(urlProps.getProperty("enable_ce") != null && urlProps.getProperty("enable_ce").equals("1")) { - urlProps.setProperty("CLIENTLOGIC", "1"); } - return urlProps; + return (long) DriverManager.getLoginTimeout() * 1000; } - } - -private static Request getRequest(URL url, String ak, String sk) throws Exception { - Request request = new Request(); - request.setUrl(url.toString()); - request.setKey(ak); - request.setSecret(sk); - return request; - } - private static String getReturn(String ak, String sk, String requestUrl,String region) throws PSQLException { - try { - URL url = new URL(requestUrl); - HttpMethodName httpMethod = HttpMethodName.GET; - Request request = getRequest(url, ak, sk); - request.setMethod(httpMethod.toString()); - request.addHeader("X-Language", "en-us"); - request.addHeader("Content-Type", "application/json"); - request.addHeader("Accept", "application/json"); - - HttpRequestBase signedRequest = Client.sign(request); - HttpResponse response = null; - - SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, - new TrustSelfSignedStrategy()).useTLS().build(); - SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, - new AllowAllHostnameVerifier()); - - client = HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build(); - - response = client.execute(signedRequest); - return convertStreamToString(response.getEntity().getContent()); - } catch (Exception e) { - throw new PSQLException (GT.tr("Get the token failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT, e); - } finally { - try { - if (client != null) { - client.close(); - } - } - catch (IOException e) { - LOGGER.warn("Catch IOException, client close failed."); - } - } - } - - private static String convertStreamToString(InputStream is) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); - StringBuilder sb = new StringBuilder(); - String line = null; - try { - while ((line = reader.readLine()) != null) { - sb.append(line + "\n"); - } - } catch (IOException ioEX) { - throw ioEX ; - } finally { - is.close(); - } - return sb.toString(); - } - - /* public method */ - public static HostSpec[] GetHostSpecs(Properties props) { - return hostSpecs(props); - } - /** - * @param props Connection properties - * @return the address portion of the orgin URL - */ - public static HostSpec[] getURLHostSpecs(Properties props) { - return urlHostSpecs(props); - } - public static String GetUser(Properties props) { - return user(props); - } - public static String GetDatabase(Properties props) { - return database(props); - } - private static HostSpec[] urlHostSpecs(Properties props) { - String[] ports = props.getProperty("PGPORTURL").split(","); - String[] hosts = props.getProperty("PGHOSTURL").split(",", ports.length); - HostSpec[] hostSpecs = new HostSpec[hosts.length]; - for (int i = 0; i < hostSpecs.length; ++i) { - hostSpecs[i] = new HostSpec(hosts[i], Integer.parseInt(ports[i])); + + /** + * This method was added in v6.5, and simply throws an SQLException for an unimplemented method. I + * decided to do it this way while implementing the JDBC2 extensions to JDBC, as it should help + * keep the overall driver size down. It now requires the call Class and the function name to help + * when the driver is used with closed software that don't report the stack strace + * + * @param callClass the call Class + * @param functionName the name of the unimplemented function with the type of its arguments + * @return PSQLException with a localized message giving the complete description of the + * unimplemeted function + */ + public static SQLFeatureNotSupportedException notImplemented(Class callClass, + String functionName) { + return new SQLFeatureNotSupportedException( + GT.tr("Method {0} is not yet implemented.", callClass.getName() + "." + functionName), + PSQLState.NOT_IMPLEMENTED.getState()); } - return hostSpecs; - } - /** - * @return the address portion of the URL - */ - private static HostSpec[] hostSpecs(Properties props) { - String[] ports = props.getProperty("PGPORT").split(","); - String[] hosts = props.getProperty("PGHOST").split(",", ports.length); - HostSpec[] hostSpecs = new HostSpec[hosts.length]; - for (int i = 0; i < hostSpecs.length; ++i) { - hostSpecs[i] = new HostSpec(hosts[i], Integer.parseInt(ports[i])); + + public java.util.logging.Logger getParentLogger() { + if (Logger.isUsingJDKLogger()) { + return PARENT_LOGGER; + } else { + return null; + } } - return hostSpecs; - } - - /** - * @return the username of the URL - */ - private static String user(Properties props) { - return props.getProperty("user", ""); - } - - /** - * @return the database name of the URL - */ - private static String database(Properties props) { - return props.getProperty("PGDBNAME", ""); - } - - /** - * @return the timeout from the URL, in milliseconds - */ - private static long timeout(Properties props) { - String timeout = PGProperty.LOGIN_TIMEOUT.get(props); - if (timeout != null) { - try { - return (long) (Float.parseFloat(timeout) * 1000); - } catch (NumberFormatException e) { - LOGGER.warn("Couldn't parse loginTimeout value: " + timeout); - } + + public static SharedTimer getSharedTimer() { + return sharedTimer; } - return (long) DriverManager.getLoginTimeout() * 1000; - } - - /** - * This method was added in v6.5, and simply throws an SQLException for an unimplemented method. I - * decided to do it this way while implementing the JDBC2 extensions to JDBC, as it should help - * keep the overall driver size down. It now requires the call Class and the function name to help - * when the driver is used with closed software that don't report the stack strace - * - * @param callClass the call Class - * @param functionName the name of the unimplemented function with the type of its arguments - * @return PSQLException with a localized message giving the complete description of the - * unimplemeted function - */ - public static SQLFeatureNotSupportedException notImplemented(Class callClass, - String functionName) { - return new SQLFeatureNotSupportedException( - GT.tr("Method {0} is not yet implemented.", callClass.getName() + "." + functionName), - PSQLState.NOT_IMPLEMENTED.getState()); - } - - public java.util.logging.Logger getParentLogger() - { - if(Logger.isUsingJDKLogger()) { - return PARENT_LOGGER; - } else { - return null; + + /** + * Register the driver against {@link DriverManager}. This is done automatically when the class is + * loaded. Dropping the driver from DriverManager's list is possible using {@link #deregister()} + * method. + * + * @throws IllegalStateException if the driver is already registered + * @throws SQLException if registering the driver fails + */ + public static void register() throws SQLException { + if (isRegistered()) { + throw new IllegalStateException( + "Driver is already registered. It can only be registered once."); + } + registeredDriver = new Driver(); + DriverManager.registerDriver(registeredDriver); + Driver.registeredDriver = registeredDriver; + + isLogFileCreated = new AtomicBoolean(false); } - } - - public static SharedTimer getSharedTimer() { - return sharedTimer; - } - - /** - * Register the driver against {@link DriverManager}. This is done automatically when the class is - * loaded. Dropping the driver from DriverManager's list is possible using {@link #deregister()} - * method. - * - * @throws IllegalStateException if the driver is already registered - * @throws SQLException if registering the driver fails - */ - public static void register() throws SQLException { - if (isRegistered()) { - throw new IllegalStateException( - "Driver is already registered. It can only be registered once."); + + /** + * According to JDBC specification, this driver is registered against {@link DriverManager} when + * the class is loaded. To avoid leaks, this method allow unregistering the driver so that the + * class can be gc'ed if necessary. + * + * @throws IllegalStateException if the driver is not registered + * @throws SQLException if deregistering the driver fails + */ + public static void deregister() throws SQLException { + if (!isRegistered()) { + throw new IllegalStateException( + "Driver is not registered (or it has not been registered using Driver.register() method)"); + } + DriverManager.deregisterDriver(registeredDriver); + registeredDriver = null; } - registeredDriver = new Driver(); - DriverManager.registerDriver(registeredDriver); - Driver.registeredDriver = registeredDriver; - - isLogFileCreated = new AtomicBoolean(false); - } - - /** - * According to JDBC specification, this driver is registered against {@link DriverManager} when - * the class is loaded. To avoid leaks, this method allow unregistering the driver so that the - * class can be gc'ed if necessary. - * - * @throws IllegalStateException if the driver is not registered - * @throws SQLException if deregistering the driver fails - */ - public static void deregister() throws SQLException { - if (!isRegistered()) { - throw new IllegalStateException( - "Driver is not registered (or it has not been registered using Driver.register() method)"); + + /** + * @return {@code true} if the driver is registered against {@link DriverManager} + */ + public static boolean isRegistered() { + return registeredDriver != null; } - DriverManager.deregisterDriver(registeredDriver); - registeredDriver = null; - } - - /** - * @return {@code true} if the driver is registered against {@link DriverManager} - */ - public static boolean isRegistered() { - return registeredDriver != null; - } - - public static String getGSVersion() - { + + public static String getGSVersion() { return gsVersion; } } diff --git a/pgjdbc/src/main/java/org/postgresql/PGProperty.java b/pgjdbc/src/main/java/org/postgresql/PGProperty.java index 309ceb9f557d3b8d2a960cd3494606ed2b18a316..5f2e216ba793fd9d4fc393daf60f2cadf46f6528 100644 --- a/pgjdbc/src/main/java/org/postgresql/PGProperty.java +++ b/pgjdbc/src/main/java/org/postgresql/PGProperty.java @@ -458,9 +458,13 @@ public enum PGProperty { * Supported TLS cipher suites */ TLS_CIPHERS_SUPPERTED("TLSCiphersSupperted", - "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256," - + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,", - "Supported TLS cipher suites"), + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256," + + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384," + + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," + + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," + + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "Supported TLS cipher suites"), /** * Factory class to instantiate factories for XML processing. @@ -641,20 +645,20 @@ public enum PGProperty { return getSetString(properties) != null; } - /** - * Convert this connection parameter and the value read from the given {@code Properties} into a - * {@code DriverPropertyInfo}. - * - * @param properties properties to take actual value from - * @return a DriverPropertyInfo representing this connection parameter - */ - public DriverPropertyInfo toDriverPropertyInfo(Properties properties) { - DriverPropertyInfo propertyInfo = new DriverPropertyInfo(_name, get(properties)); - propertyInfo.required = _required; - propertyInfo.description = _description; - propertyInfo.choices = _choices; - return propertyInfo; - } + /** + * Convert this connection parameter and the value read from the given {@code Properties} into a + * {@code DriverPropertyInfo}. + * + * @param properties properties to take actual value from + * @return a DriverPropertyInfo representing this connection parameter + */ + public DriverPropertyInfo toDriverPropertyInfo(Properties properties) { + DriverPropertyInfo propertyInfo = new DriverPropertyInfo(_name, get(properties)); + propertyInfo.required = _required; + propertyInfo.description = _description; + propertyInfo.choices = _choices; + return propertyInfo; + } public static PGProperty forName(String name) { for (PGProperty property : PGProperty.values()) { diff --git a/pgjdbc/src/main/java/org/postgresql/core/CachedQuery.java b/pgjdbc/src/main/java/org/postgresql/core/CachedQuery.java index 23ac4cd05aa09c9d74d361b6ac20fc674dc76774..afd96023d36ad6331156c82faa727375eaa6136c 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/CachedQuery.java +++ b/pgjdbc/src/main/java/org/postgresql/core/CachedQuery.java @@ -18,16 +18,18 @@ public class CachedQuery implements CanEstimateSize { public final Object key; public final Query query; public final boolean isFunction; - + public final boolean isACompatibilityFunction; private int executeCount; - public CachedQuery(Object key, Query query, boolean isFunction) { + public CachedQuery(Object key, Query query, boolean isFunction, boolean isACompatibilityFunction) { assert key instanceof String || key instanceof CanEstimateSize : "CachedQuery.key should either be String or implement CanEstimateSize." + " Actual class is " + key.getClass(); this.key = key; this.query = query; this.isFunction = isFunction; + this.isACompatibilityFunction = isACompatibilityFunction; + this.query.setIsFunction(isFunction); } public void increaseExecuteCount() { diff --git a/pgjdbc/src/main/java/org/postgresql/core/CachedQueryCreateAction.java b/pgjdbc/src/main/java/org/postgresql/core/CachedQueryCreateAction.java index df74aa2b62c5787f4c60d04168804e12cf549047..b77a6f237e302b5eb512679eb3ffd3538da75df2 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/CachedQueryCreateAction.java +++ b/pgjdbc/src/main/java/org/postgresql/core/CachedQueryCreateAction.java @@ -41,14 +41,17 @@ class CachedQueryCreateAction implements LruCache.CreateAction= 0; @@ -65,6 +68,6 @@ class CachedQueryCreateAction implements LruCache.CreateAction OID_TO_NAME = new HashMap(100); private static final Map NAME_TO_OID = new HashMap(100); diff --git a/pgjdbc/src/main/java/org/postgresql/core/ParameterList.java b/pgjdbc/src/main/java/org/postgresql/core/ParameterList.java index bbfa51be4b800482eec2f225e39ebdb640e58472..0b09f427df13e69ba8fed06a771b0325df2c3842 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/ParameterList.java +++ b/pgjdbc/src/main/java/org/postgresql/core/ParameterList.java @@ -242,4 +242,6 @@ public interface ParameterList { * @return Object array containing the parameter values. */ Object[] getValues(); + + void bindRegisterOutParameter(int index,int oid, boolean isACompatibilityFunction) throws SQLException; } diff --git a/pgjdbc/src/main/java/org/postgresql/core/Parser.java b/pgjdbc/src/main/java/org/postgresql/core/Parser.java index ffe081846e452a797dc268d1c423932623cb1836..c18a059894273603bfb288140d46c28b36ff05ff 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/Parser.java +++ b/pgjdbc/src/main/java/org/postgresql/core/Parser.java @@ -48,8 +48,6 @@ public class Parser { boolean isBatchedReWriteConfigured, String... returningColumnNames) throws SQLException { int numOfOverSymble = 0; - boolean haveProcedure = false; - boolean haveFunction = false; if(startWithComment(query)) { query = removeFirstComment(query); } @@ -57,15 +55,7 @@ public class Parser { String queryTemp = query.trim(); queryTemp = queryTemp.replaceAll(reg, "\0"); String[] queryArr = queryTemp.split("\0"); - - for(int i = 0;i < queryArr.length; i++) { - if (queryArr[i] != null && (queryArr[i].toUpperCase(Locale.ENGLISH)).equals("PROCEDURE") ) { - haveProcedure = true; - } - if (queryArr[i] != null && (queryArr[i].toUpperCase(Locale.ENGLISH)).equals("FUNCTION") ) { - haveFunction = true; - } - } + boolean haveSpecialKeyword = isContainSpecialKeyword(queryArr); if (!withParameters && !splitStatements && returningColumnNames != null && returningColumnNames.length == 0) { @@ -135,7 +125,11 @@ public class Parser { { break; } - if (i >1 && "\n".equals(String.valueOf(aChars[i - 1]))) { + if (!haveSpecialKeyword) { + break; + } + + if (i > 1 && ("\n".equals(String.valueOf(aChars[i - 1])) || " ".equals(String.valueOf(aChars[i - 1])))) { numOfOverSymble++; if (inParen == 0) { if (!whitespaceOnly) { @@ -165,6 +159,7 @@ public class Parser { valuesBraceClosePosition = -1; } + inBeginEnd = 0; nativeQueries.add( new NativeQuery( nativeSql.toString(), @@ -236,11 +231,7 @@ public class Parser { break; case ';': - if (haveProcedure || haveFunction) - { - break; - } - if (queryArr[0] !=null && ((queryArr[0].toUpperCase(Locale.ENGLISH)).equals("BEGIN") ||(queryArr[0].toUpperCase(Locale.ENGLISH)).equals("DECLARE"))) + if (haveSpecialKeyword) { break; } @@ -268,7 +259,7 @@ public class Parser { valuesBraceOpenPosition = -1; valuesBraceClosePosition = -1; } - + inBeginEnd = 0; nativeQueries.add(new NativeQuery(nativeSql.toString(), toIntArray(bindPositions), false, SqlCommand.createStatementTypeInfo( @@ -304,7 +295,7 @@ public class Parser { && "N".equalsIgnoreCase(String.valueOf(aChars[i + 4])) && isSpecialCharacters(aChars[i - 1]) && isSpecialCharacters(aChars[i + 5])) { - inBeginEnd ++; + inBeginEnd++; } } break; @@ -315,7 +306,9 @@ public class Parser { if ("N".equalsIgnoreCase(String.valueOf(aChars[i + 1])) && "D".equalsIgnoreCase(String.valueOf(aChars[i + 2]))) { - inBeginEnd --; + int[] result = parseEnd(i, aChars, inBeginEnd); + i = result[0]; + inBeginEnd = result[1]; } } @@ -615,6 +608,48 @@ public class Parser { return query.length; } + /** + * Judge whether the statement contains the keywords procedure, function, create, package and declare + * + * @param queryArr An array of strings consisting of SQL statements + * @return boolean + */ + private static boolean isContainSpecialKeyword(final String[] queryArr) { + if (queryArr[0].toUpperCase(Locale.ENGLISH).equals("BEGIN")) { + return true; + } + boolean haveCreate = false; + boolean havePackage = false; + for (int i = 0; i < queryArr.length; i++) { + if (queryArr[i] == null) { + continue; + } + switch (queryArr[i].toUpperCase(Locale.ENGLISH)) { + case "PROCEDURE": + case "FUNCTION": + case "DECLARE": + return true; + case "CREATE": + if (i == 0) { + haveCreate = true; + } + break; + case "PACKAGE": + havePackage = true; + break; + case "END": + if (haveCreate && havePackage) { + // Case : create package tn end is end tn; + return true; + } + break; + default: + break; + } + } + return false; + } + /** *

Find the end of the double-quoted string starting at the given offset.

* @@ -1092,6 +1127,7 @@ public class Parser { String sql = jdbcSql; boolean isFunction = false; boolean outParamBeforeFunc = false; + boolean isACompatibilityFunction = false; int len = jdbcSql.length(); int state = 1; @@ -1122,6 +1158,7 @@ public class Parser { if (ch == '?') { outParamBeforeFunc = isFunction = true; // { ? = call ... } -- function with one out parameter + isACompatibilityFunction = true; ++i; ++state; } else if (ch == 'c' || ch == 'C') { // { call ... } -- proc with no out parameters @@ -1223,7 +1260,7 @@ public class Parser { if (i == len && !syntaxError) { if (state == 1) { // Not an escaped syntax. - return new JdbcCallParseInfo(sql, isFunction); + return new JdbcCallParseInfo(sql, isFunction, false); } if (state != 8) { syntaxError = true; // Ran out of query while still parsing @@ -1277,7 +1314,7 @@ public class Parser { } sql = sb.append(suffix).toString(); - return new JdbcCallParseInfo(sql, isFunction); + return new JdbcCallParseInfo(sql, isFunction, isACompatibilityFunction); } /** @@ -1475,6 +1512,47 @@ public class Parser { return i; } + /** + * Judge whether the current end is the end paired with begin + */ + private static int[] parseEnd(final int offset, final char[] query, final int inBeginEnd) { + int tempOffset = offset; + int tempInBeginEnd = inBeginEnd; + tempOffset = tempOffset + 3; + while (tempOffset < query.length) { + if (isSpecialCharacters(query[tempOffset])) { + tempOffset++; + } else if ("-".equals(String.valueOf(query[tempOffset]))) { + int temp = tempOffset; + tempOffset = Parser.parseLineComment(query, tempOffset); + if (temp == tempOffset) { + tempOffset++; + } + } else if ("/".equals(String.valueOf(query[tempOffset]))) { + int temp = tempOffset; + temp = Parser.parseBlockComment(query, temp); + if (tempOffset != temp) { + tempOffset = temp + 1; + } else { + // Not a slash for a comment + tempOffset--; + tempInBeginEnd--; + break; + } + } else if (";".equals(String.valueOf(query[tempOffset])) + || (tempOffset + 1 < query.length && "$$".equals( + String.valueOf(query[tempOffset]) + query[tempOffset + 1]))) { + // This is the end paired with begin + tempInBeginEnd--; + break; + } else { + tempOffset--; + break; + } + } + return new int[]{tempOffset, tempInBeginEnd}; + } + /** * Generate sql for escaped functions. * diff --git a/pgjdbc/src/main/java/org/postgresql/core/Query.java b/pgjdbc/src/main/java/org/postgresql/core/Query.java index eeda70426a21d0d2fa25df0dbc26a09650e5f53c..2beac88e6054a36e004503084cdd1ebbef8160c5 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/Query.java +++ b/pgjdbc/src/main/java/org/postgresql/core/Query.java @@ -90,4 +90,19 @@ public interface Query { * single-statement query. */ Query[] getSubqueries(); + + /** + * Set the current statement state + * + * @param isFunction true or false + */ + void setIsFunction(boolean isFunction); + + /** + * Returns whether the current statement is a function + * + * @return true or false + * + */ + boolean getIsFunction(); } diff --git a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java index e02e9a28ec23ac362a77b736a28eab6a5cc023ad..f6878f23607a0b4cd2ffeda057d9ebbe01f6f763 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java +++ b/pgjdbc/src/main/java/org/postgresql/core/QueryExecutor.java @@ -496,4 +496,22 @@ public interface QueryExecutor extends TypeTransferModeRegistry { void setGaussdbVersion(String gaussdbVersion); void setAvailability(boolean availability); + + String getCompatibilityMode(); + + void setCompatibilityMode(String compatibilityMode); + + /** + * Get reload status + * + * @return state true or false + */ + boolean getEnableOutparamOveride(); + + /** + * Set reload status + * + * @param enableOutparamOveride true or false + */ + void setEnableOutparamOveride(boolean enableOutparamOveride); } diff --git a/pgjdbc/src/main/java/org/postgresql/core/SocketFactoryFactory.java b/pgjdbc/src/main/java/org/postgresql/core/SocketFactoryFactory.java index 09efa75f075daeafc1553f3fb8a0bf3acc5de233..fe56354a21ff3b1992947c8fe4d476512ad81bd2 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/SocketFactoryFactory.java +++ b/pgjdbc/src/main/java/org/postgresql/core/SocketFactoryFactory.java @@ -36,7 +36,7 @@ public class SocketFactoryFactory { return SocketFactory.getDefault(); } try { - return (SocketFactory) ObjectFactory.instantiate(socketFactoryClassName, info, true, + return ObjectFactory.instantiate(SocketFactory.class, socketFactoryClassName, info, true, PGProperty.SOCKET_FACTORY_ARG.get(info)); } catch (Exception e) { throw new PSQLException( @@ -61,7 +61,7 @@ public class SocketFactoryFactory { return new LibPQFactory(info); } try { - return (SSLSocketFactory) ObjectFactory.instantiate(classname, info, true, + return ObjectFactory.instantiate(SSLSocketFactory.class, classname, info, true, PGProperty.SSL_FACTORY_ARG.get(info)); } catch (Exception e) { throw new PSQLException( diff --git a/pgjdbc/src/main/java/org/postgresql/core/Utils.java b/pgjdbc/src/main/java/org/postgresql/core/Utils.java index 027c71a5b7cdb94a052fb1ca9f8cc701aff1863b..7b1c9d7fec1039e8896f280497b10f3998a574ea 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/Utils.java +++ b/pgjdbc/src/main/java/org/postgresql/core/Utils.java @@ -34,12 +34,6 @@ public class Utils { return sb.toString(); } - /** - * Keep a local copy of the UTF-8 Charset so we can avoid synchronization overhead from looking up - * the Charset by name as String.getBytes(String) requires. - */ - private static final Charset utf8Charset = Charset.forName("UTF-8"); - /** * Encode a string as UTF-8. * @@ -51,12 +45,7 @@ public class Utils { // for performance measurements. // In OracleJDK 6u65, 7u55, and 8u40 String.getBytes(Charset) is // 3 times faster than other JDK approaches. - Charset gbkCharset = Charset.forName("GBK"); - if ("GBK".equals((ConnectionFactoryImpl.CLIENT_ENCODING).toUpperCase(Locale.ENGLISH))) - { - return str.getBytes(gbkCharset); - } - return str.getBytes(utf8Charset); + return str.getBytes(Charset.forName(ConnectionFactoryImpl.CLIENT_ENCODING)); } /** diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeParameterList.java b/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeParameterList.java index f5e1948fe2a55e4100f3615451ff9c92e1a50f3d..9441cc5fbeb60b119aed81c24fd75298aedfb5cb 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeParameterList.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeParameterList.java @@ -47,6 +47,11 @@ class CompositeParameterList implements V3ParameterList { } + @Override + public void bindRegisterOutParameter(int index, int oid, boolean isACompatibilityFunction) throws SQLException { + + } + public int getDirection(int i) { return 0; } diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeQuery.java b/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeQuery.java index 77809e434a53a1c3674ab50d08c28728ee41322d..33f2b5dcec01b1b2c365d799a8c17b33ba4dfc9e 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeQuery.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/CompositeQuery.java @@ -76,6 +76,16 @@ class CompositeQuery implements Query { return subqueries; } + @Override + public void setIsFunction(boolean isFunction) { + + } + + @Override + public boolean getIsFunction() { + return false; + } + public boolean isStatementDescribed() { for (SimpleQuery subquery : subqueries) { if (!subquery.isStatementDescribed()) { diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java b/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java index 9bd230dd2d4564bed5bf1bab51fd6bb571203972..cc0e07ea9636b0f9f8fdd42328a9dbc97e21a5b2 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/ConnectionFactoryImpl.java @@ -72,6 +72,18 @@ public class ConnectionFactoryImpl extends ConnectionFactory { private static final int PROTOCOL_VERSION_350 = 350; private int protocolVerion = PROTOCOL_VERSION_351; private String connectInfo = ""; + + /** + * Whitelist of supported client_encoding + */ + public static final HashMap CLIENT_ENCODING_WHITELIST = new HashMap<>(); + + static { + CLIENT_ENCODING_WHITELIST.put("UTF8", "UTF8"); + CLIENT_ENCODING_WHITELIST.put("UTF-8", "UTF-8"); + CLIENT_ENCODING_WHITELIST.put("GBK", "GBK"); + CLIENT_ENCODING_WHITELIST.put("LATIN1", "LATIN1"); + } public static void setStaticClientEncoding(String client) { ConnectionFactoryImpl.CLIENT_ENCODING = client; } @@ -158,9 +170,12 @@ public class ConnectionFactoryImpl extends ConnectionFactory { public QueryExecutor openConnectionImpl(HostSpec[] hostSpecs, String user, String database, Properties info) throws SQLException { if (info.getProperty("characterEncoding") != null) { - if ("UTF8".equals((info.getProperty("characterEncoding")).toUpperCase(Locale.ENGLISH)) - || "GBK".equals((info.getProperty("characterEncoding")).toUpperCase(Locale.ENGLISH))) { - setClientEncoding(info.getProperty("characterEncoding")); + if (CLIENT_ENCODING_WHITELIST.containsKey((info.getProperty("characterEncoding")).toUpperCase(Locale.ENGLISH))) { + setClientEncoding(info.getProperty("characterEncoding").toUpperCase(Locale.ENGLISH)); + } else { + LOGGER.warn("unsupported client_encoding: " + info.getProperty( + "characterEncoding") + ", to ensure correct operation, please use the specified range " + + "of client_encoding."); } } @@ -304,10 +319,13 @@ public class ConnectionFactoryImpl extends ConnectionFactory { continue; } - //query and update statements cause logical replication to fail, temporarily evade + // query and update statements cause logical replication to fail, temporarily evade if (info.getProperty("replication") == null) { runInitialQueries(queryExecutor, info); - queryExecutor.setGaussdbVersion(queryGaussdbVersion(queryExecutor)); + String queryGaussdbVersionResult = queryGaussdbVersion(queryExecutor); + queryExecutor.setGaussdbVersion(queryGaussdbVersionResult); + // get database compatibility mode + queryExecutor.setCompatibilityMode(queryDataBaseDatcompatibility(queryExecutor, database)); } if (MultiHostChooser.isUsingAutoLoadBalance(info)) { QueryCNListUtils.runRereshCNListQueryies(queryExecutor, info); @@ -715,7 +733,7 @@ public class ConnectionFactoryImpl extends ConnectionFactory { } else { throw new PSQLException( GT.tr( - "The password-stored method is not supported, must be md5, " + "The password-stored method is not supported, must be md5, " + "sha256 or sm3."), PSQLState.CONNECTION_REJECTED); } @@ -838,6 +856,15 @@ public class ConnectionFactoryImpl extends ConnectionFactory { return localRole.equalsIgnoreCase("Primary") && dbState.equalsIgnoreCase("Normal"); } + private String queryDataBaseDatcompatibility(QueryExecutor queryExecutor, String database) throws SQLException, + IOException { + byte[][] result = SetupQueryRunner.run(queryExecutor, "select datcompatibility from pg_database where " + + "datname='" + database + "';", true); + String datcompatibility = queryExecutor.getEncoding().decode(result[0]); + return datcompatibility == null ? "PG" : datcompatibility; + } + + private String queryGaussdbVersion(QueryExecutor queryExecutor) throws SQLException, IOException { byte[][] result = SetupQueryRunner.run(queryExecutor, "select version();", true); String version = queryExecutor.getEncoding().decode(result[0]); diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java index 332e4d2daf184737c5224380f77d1f730ff16f10..455dd54cc53bed588de848af345af6cbdda1320a 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/QueryExecutorImpl.java @@ -5,6 +5,7 @@ // Copyright (c) 2004, Open Cloud Limited. package org.postgresql.core.v3; +import org.postgresql.Driver; import org.postgresql.PGProperty; import org.postgresql.copy.CopyIn; import org.postgresql.copy.CopyOperation; @@ -51,7 +52,6 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.sql.SQLException; import java.sql.SQLWarning; -import java.sql.Statement; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -123,6 +123,11 @@ public class QueryExecutorImpl extends QueryExecutorBase { private String socketAddress; private String gaussdbVersion; + + private String compatibilityMode; + + private boolean enableOutparamOveride; + /** * {@code CommandComplete(B)} messages are quite common, so we reuse instance to parse those */ @@ -160,6 +165,34 @@ public class QueryExecutorImpl extends QueryExecutorBase { this.gaussdbVersion = gaussdbVersion; } + @Override + public String getCompatibilityMode() { + return compatibilityMode; + } + + public void setCompatibilityMode(String compatibilityMode) { + this.compatibilityMode = compatibilityMode; + } + + @Override + public boolean getEnableOutparamOveride() { + return enableOutparamOveride; + } + + public void setEnableOutparamOveride(boolean enableOutparamOveride) { + this.enableOutparamOveride = enableOutparamOveride; + } + + /** + * When database compatibility mode is A database and the parameter overload function + * is turned on, add out parameter description message. + * + * @return true: describe, false: not describe. + */ + private boolean isDescribeOutparam() { + return enableOutparamOveride && ("A".equals(compatibilityMode) || "ORA".equals(compatibilityMode)); + } + /** *

Supplement to synchronization of public methods on current QueryExecutor.

* @@ -1541,6 +1574,27 @@ public class QueryExecutorImpl extends QueryExecutorBase { byte[] encodedStatementName = query.getEncodedStatementName(); String nativeSql = query.getNativeSql(); + boolean sendFunctionParamType = isSendFunctionParamType(query); + char[] paramFlags = new char[params.getFlags().length]; + + if (sendFunctionParamType) { + byte[] flags = params.getFlags(); + for (int j = 0; j < flags.length; j++) { + switch (flags[j]) { + case 1: + paramFlags[j] = 'i'; + break; + case 2: + paramFlags[j] = 'o'; + break; + case 3: + paramFlags[j] = 'b'; + break; + default: + paramFlags[j] = 'i'; + } + } + } if (LOGGER.isTraceEnabled()) { StringBuilder sbuf = new StringBuilder(" FE=> Parse(stmt=" + statementName + ",query=\""); sbuf.append(nativeSql); @@ -1551,6 +1605,15 @@ public class QueryExecutorImpl extends QueryExecutorBase { } sbuf.append(params.getTypeOID(i)); } + if (sendFunctionParamType) { + sbuf.append("}\",flags={"); + for (int i = 1; i <= paramFlags.length; ++i) { + if (i != 1) { + sbuf.append(","); + } + sbuf.append(paramFlags[i - 1]); + } + } sbuf.append("})"); LOGGER.trace("[" + socketAddress + "] " + sbuf.toString()); } @@ -1565,10 +1628,15 @@ public class QueryExecutorImpl extends QueryExecutorBase { // + N + 1 (statement name, zero-terminated) // + N + 1 (query, zero terminated) // + 2 (parameter count) + N * 4 (parameter types) + // + 2 or 0 (if overload + 2 else + 0) + // + params.getFlags().length or 0 (if oracle compatibilityMode & overload & sql is function or procedure send + // length else nosend) int encodedSize = 4 + (encodedStatementName == null ? 0 : encodedStatementName.length) + 1 + queryUtf8.length + 1 - + 2 + 4 * params.getParameterCount(); + + 2 + 4 * params.getParameterCount() + + (this.getEnableOutparamOveride() ? 2 : 0) + + (sendFunctionParamType ? params.getFlags().length : 0); pgStream.sendChar('P'); // Parse pgStream.sendInteger4(encodedSize); @@ -1582,7 +1650,16 @@ public class QueryExecutorImpl extends QueryExecutorBase { for (int i = 1; i <= params.getParameterCount(); ++i) { pgStream.sendInteger4(params.getTypeOID(i)); } - + if (this.getEnableOutparamOveride()) { + if (sendFunctionParamType) { + pgStream.sendInteger2(params.getParameterCount()); + for (int i = 1; i <= paramFlags.length; ++i) { + pgStream.sendChar(paramFlags[i - 1]); + } + } else { + pgStream.sendInteger2(0); + } + } pendingParseQueue.add(query); } @@ -3039,6 +3116,12 @@ public class QueryExecutorImpl extends QueryExecutorBase { throw new PSQLException(GT.tr("Protocol error. Session setup failed."), PSQLState.PROTOCOL_VIOLATION); } + } else if ("behavior_compat_options".equals(name)) { + if (value != null && value.contains("proc_outparam_override")) { + setEnableOutparamOveride(true); + } else { + setEnableOutparamOveride(false); + } } } @@ -3099,6 +3182,23 @@ public class QueryExecutorImpl extends QueryExecutorBase { useBinarySendForOids.addAll(oids); } + /** + * In oracle compatibility mode, turn on output parameter overload (enable_outparam_overide=true) and + * sql is a function or a stored procedure. At this time, need to send the type of function and stored + * procedure parameters (in or out) + * + * @param query Current SQL + * @return true or false + */ + private boolean isSendFunctionParamType(Query query) { + if (("ORA".equals(this.getCompatibilityMode()) || "A".equals(this.getCompatibilityMode())) + && this.getEnableOutparamOveride() && query.getIsFunction()) { + return true; + } else { + return false; + } + } + private void setIntegerDateTimes(boolean state) { integerDateTimes = state; } diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleParameterList.java b/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleParameterList.java index 12bdd836dbc00a550c73d0ee9a18c74361728a75..4ecceb6f2b536621809a373c7354d5008df323c1 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleParameterList.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleParameterList.java @@ -49,6 +49,8 @@ class SimpleParameterList implements V3ParameterList { this.encoded = new byte[paramCount][]; this.flags = new byte[paramCount]; this.transferModeRegistry = transferModeRegistry; + this.compatibilityModes = new String[paramCount]; + this.isACompatibilityFunctions = new boolean[paramCount]; } @Override @@ -63,6 +65,19 @@ class SimpleParameterList implements V3ParameterList { flags[index - 1] |= OUT; } + @Override + public void bindRegisterOutParameter(int index, int oid, boolean isACompatibilityFunction) throws SQLException { + if (index < 1 || index > paramValues.length) { + throw new PSQLException( + GT.tr("The column index is out of range: {0}, number of columns: {1}.", + index, paramValues.length), + PSQLState.INVALID_PARAMETER_VALUE); + } + paramTypes[index - 1] = oid; + compatibilityModes[index - 1] = "ORA"; + isACompatibilityFunctions[index - 1] = isACompatibilityFunction; + } + private void bind(int index, Object value, int oid, byte binary) throws SQLException { if (index < 1 || index > paramValues.length) { throw new PSQLException( @@ -314,8 +329,16 @@ class SimpleParameterList implements V3ParameterList { public void convertFunctionOutParameters() { for (int i = 0; i < paramTypes.length; ++i) { if (direction(i) == OUT) { - paramTypes[i] = Oid.VOID; - paramValues[i] = "null"; + if(compatibilityModes[i] != null && compatibilityModes[i].equalsIgnoreCase("ORA")){ + // function return value as void. + if (isACompatibilityFunctions[i] == true && i == 0) { + paramTypes[i] = Oid.VOID; + } + paramValues[i] = "null"; + }else{ + paramTypes[i] = Oid.VOID; + paramValues[i] = "null"; + } } } } @@ -514,6 +537,8 @@ class SimpleParameterList implements V3ParameterList { private final byte[] flags; private final byte[][] encoded; private final TypeTransferModeRegistry transferModeRegistry; + private final boolean[] isACompatibilityFunctions; + private final String[] compatibilityModes; /** * Marker object representing NULL; this distinguishes "parameter never set" from "parameter set diff --git a/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleQuery.java b/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleQuery.java index 9d464f102632f25f5ce8577ce4600fa1956d2309..1f5d3d63709ca9f6abe9bf9b250e9f7f87b26a8a 100644 --- a/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleQuery.java +++ b/pgjdbc/src/main/java/org/postgresql/core/v3/SimpleQuery.java @@ -67,6 +67,16 @@ class SimpleQuery implements Query { return null; } + @Override + public void setIsFunction(boolean isFunction) { + this.isFunction = isFunction; + } + + @Override + public boolean getIsFunction() { + return this.isFunction; + } + /** *

Return maximum size in bytes that each result row from this query may return. Mainly used for * batches that return results.

@@ -367,6 +377,7 @@ class SimpleQuery implements Query { private int[] preparedTypes; private BitSet unspecifiedParams; private short deallocateEpoch; + private boolean isFunction; private Integer cachedMaxResultRowSize; diff --git a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java index db6e6568875ac74dda2a4442156ee7fd0020674a..63148287f4afaae588cfdcab2986b97b4caf989e 100644 --- a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java +++ b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java @@ -43,6 +43,7 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable private static Log LOGGER = Logger.getLogger(BaseDataSource.class.getName()); // Standard properties, defined in the JDBC 2.0 Optional Package spec + private String originUrl; private String serverName = "localhost"; private String databaseName; private String user; @@ -1116,6 +1117,9 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable * @return {@link DriverManager} URL from the other properties supplied */ public String getUrl() { + if (this.originUrl != null && this.originUrl.length() > 0 && this.databaseName == null) { + return this.originUrl; + } StringBuilder url = new StringBuilder(100); url.append("jdbc:postgresql://"); url.append(serverName); @@ -1163,7 +1167,7 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable * @throws PSQLException */ public void setUrl(String url) throws PSQLException { - + this.originUrl = url; Properties p = org.postgresql.Driver.parseURL(url, null); for (PGProperty property : PGProperty.values()) { diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogic.java b/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogic.java index d9fd754db1b73612fc849c6f51526fbe95b890c5..79fe53a2bf487ca43f973bd052deba51cf3a5b84 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogic.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogic.java @@ -115,7 +115,7 @@ public class ClientLogic { */ protected void finalize() { close(); - } + } /** * Link the client logic JNI & C side to the PgConnection instance @@ -142,11 +142,11 @@ public class ClientLogic { if (handle == 0 || handle < 0) { throw new ClientLogicException(ERROR_INVALID_HANDLE, ERROR_TEXT_INVALID_HANDLE); } - impl.setHandle(handle); + impl.setHandle(handle); } /** - * Runs the pre-process function of the client logic + * Runs the pre-process function of the client logic * to change the client logic fields from the user input to the client logic format * @param originalQuery query to modify with user input * @return the modified query with client logic fields changed diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogicImpl.java b/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogicImpl.java index f938e2913a6692ede89943861f4169bcfcbbe6bb..1dadc23cb716317eca80405e17bf4cdd67758444 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogicImpl.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/ClientLogicImpl.java @@ -41,7 +41,7 @@ public class ClientLogicImpl { else { //did not add much logic here, will handle it on the parent class return new Object[]{}; - } + } } /** @@ -56,9 +56,9 @@ public class ClientLogicImpl { return runQueryPreProcessImpl(m_handle, originalQuery); } /** - * Replace client logic field value with user input - used when receiving data in a resultset + * Replace client logic field value with user input - used when receiving data in a resultset * @param processData the data in binary format (hexa) - * @param dataType the oid (modid) of the original field type + * @param dataType the oid (modid) of the original field type * @return array of objects *[0][0] - int status code - zero for success *[0][1] - string status description @@ -84,13 +84,13 @@ public class ClientLogicImpl { * @return array of objects *[0][0] - int status code - zero for success *[0][1] - string status description - *[1] - String - The modified query - to be used if the query had client logic fields in user format that have to be replaces with binary value + *[1] - String - The modified query - to be used if the query had client logic fields in user format that have to be replaces with binary value */ public Object[] prepareQuery(String query, String statement_name, int parameter_count){ return prepareQueryImpl(m_handle, query, statement_name, parameter_count); } /** - * replace parameters values in prepared statement - to be called before binding the parameters and executing the statement + * replace parameters values in prepared statement - to be called before binding the parameters and executing the statement * @param statementName the name of the statement * @param paramValues array of parameters in user format * @return array of objects @@ -108,7 +108,7 @@ public class ClientLogicImpl { * ... Key (name)=(\xa1d4....) already exists. ... * to: * ... Key (name)=(John) already exists. ... - * @param originalMessage the error message received from the server + * @param originalMessage the error message received from the server * @return array of objects *[0][0] - int status code - zero for success *[0][1] - string status description @@ -134,7 +134,7 @@ public class ClientLogicImpl { } /** - * setter function to set the handle + * setter function to set the handle * @param handle */ public void setHandle(long handle) { @@ -149,9 +149,9 @@ public class ClientLogicImpl { } /** - * This method is being invoked from the client logic c++ code - * It is used to fetch data from the server regarding the client logic settings - cache manager - * @param query the query to incoke + * This method is being invoked from the client logic c++ code + * It is used to fetch data from the server regarding the client logic settings - cache manager + * @param query the query to incoke * @return array of results in the following format * [0] - array of column headers * [1...n] - array of results @@ -184,7 +184,7 @@ public class ClientLogicImpl { data.add(record.toArray()); } st.close(); - } + } catch (SQLException e) { List errorResponse = new ArrayList<>(); errorResponse.add(e.getMessage()); diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallableStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallableStatement.java index ed58df8aad6b34a1f421a91b077279b9f9439d85..d205df0da13648c33d084d47ddfad1725fdc21b7 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallableStatement.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallableStatement.java @@ -6,11 +6,15 @@ package org.postgresql.jdbc; import org.postgresql.Driver; +import org.postgresql.core.BaseStatement; +import org.postgresql.core.Oid; import org.postgresql.core.ParameterList; import org.postgresql.core.Query; +import org.postgresql.core.QueryExecutor; import org.postgresql.core.types.PGBlob; import org.postgresql.core.types.PGClob; import org.postgresql.util.GT; +import org.postgresql.util.PGobject; import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLState; @@ -22,6 +26,7 @@ import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.NClob; +import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.RowId; @@ -30,8 +35,12 @@ import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; +import java.util.ArrayList; import java.util.Calendar; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; class PgCallableStatement extends PgPreparedStatement implements CallableStatement { // Used by the callablestatement style methods @@ -45,12 +54,24 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme private boolean returnTypeSet; protected Object[] callResult; private int lastIndex = 0; + private String compatibilityMode; + private boolean isACompatibilityFunction; + private boolean enableOutparamOveride; + // cache the subscript of the current custom type in the statement and the struct of the custom type + private ConcurrentHashMap> compositeTypeStructMap = new ConcurrentHashMap<>(); + // whether the current executed SQL statement contains a custom type + private boolean isContainCompositeType = false; + private PreparedStatement getCompositeTypeStatementSimple; + // cache custom types that have been queried + private ConcurrentHashMap> compositeTypeMap = new ConcurrentHashMap<>(); PgCallableStatement(PgConnection connection, String sql, int rsType, int rsConcurrency, int rsHoldability) throws SQLException { super(connection, connection.borrowCallableQuery(sql), rsType, rsConcurrency, rsHoldability); this.isFunction = preparedQuery.isFunction; - + this.isACompatibilityFunction = preparedQuery.isACompatibilityFunction; + this.compatibilityMode = connection.getQueryExecutor().getCompatibilityMode(); + this.enableOutparamOveride = connection.getQueryExecutor().getEnableOutparamOveride(); if (this.isFunction) { int inParamCount = this.preparedParameters.getInParameterCount() + 1; this.testReturn = new int[inParamCount]; @@ -85,7 +106,7 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme // callable statement function set the return data if (!hasResultSet) { throw new PSQLException(GT.tr("A CallableStatement was executed with nothing returned."), - PSQLState.NO_DATA); + PSQLState.NO_DATA); } ResultSet rs; @@ -95,7 +116,7 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme } if (!rs.next()) { throw new PSQLException(GT.tr("A CallableStatement was executed with nothing returned."), - PSQLState.NO_DATA); + PSQLState.NO_DATA); } // figure out how many columns @@ -103,52 +124,92 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme int outParameterCount = preparedParameters.getOutParameterCount(); - if (cols != outParameterCount) { - throw new PSQLException( - GT.tr("A CallableStatement was executed with an invalid number of parameters"), - PSQLState.SYNTAX_ERROR); - } - // reset last result fetched (for wasNull) lastIndex = 0; // allocate enough space for all possible parameters without regard to in/out callResult = new Object[preparedParameters.getParameterCount() + 1]; - // move them into the result set - for (int i = 0, j = 0; i < cols; i++, j++) { - // find the next out parameter, the assumption is that the functionReturnType - // array will be initialized with 0 and only out parameters will have values - // other than 0. 0 is the value for java.sql.Types.NULL, which should not - // conflict - while (j < functionReturnType.length && functionReturnType[j] == 0) { - j++; - } - - callResult[j] = rs.getObject(i + 1); - int columnType = rs.getMetaData().getColumnType(i + 1); - - if (columnType != functionReturnType[j]) { - // this is here for the sole purpose of passing the cts - PgCallstatementTypeCompatibility typeCompatibility = new PgCallstatementTypeCompatibility( - columnType, - functionReturnType[j]); - if (typeCompatibility.isCompatibilityType()) { - if (callResult[j] != null && typeCompatibility.needConvert()) { - callResult[j] = typeCompatibility.convert(callResult[j]); - } + if (isContainCompositeType && outParameterCount == 1) { + for (int i = 0, j = 0; i < cols; i++, j++) { + while (j < functionReturnType.length && functionReturnType[j] == 0) { + j++; } - else if ( columnType == Types.BLOB && functionReturnType[j] == Types.OTHER ) - { + if (compositeTypeStructMap.get(j + 1) == null) { + throw new PSQLException(GT.tr("Unknown composite type."), PSQLState.UNKNOWN_STATE); } - else { - throw new PSQLException(GT.tr( - "A CallableStatement function was executed and the out parameter {0} was of type {1} however type {2} was registered.", - i + 1, "java.sql.Types=" + columnType, "java.sql.Types=" + functionReturnType[j]), - PSQLState.DATA_TYPE_MISMATCH); + int compositeTypeLength = compositeTypeStructMap.get(j + 1).size(); + StringBuffer sb = new StringBuffer(); + sb.append("("); + for (int k = 0; k < compositeTypeLength; k++, i++) { + String str = rs.getString(i + 1); + if (str != null) { + if (isContainSpecialChar(str)) { + // escape double quotes. + if (str.contains(Character.toString('"'))) { + str = str.replaceAll("\"", "\"\""); + } + // escape backslashes. + if (str.contains(Character.toString('\\'))) { + str = str.replaceAll("\\\\", "\\\\\\\\"); + } + sb.append("\"" + str + "\"" + ","); + } else { + sb.append(str + ","); + } + } else { + sb.append(","); + } } + sb.deleteCharAt(sb.length() - 1); + sb.append(")"); + PGobject pGobject = (PGobject) connection.getObject("null", sb.toString(), null); + pGobject.setStruct(getcompositeTypeStruct(j + 1)); + callResult[j] = pGobject; + } + } else { + if (cols != outParameterCount) { + throw new PSQLException( + GT.tr("A CallableStatement was executed with an invalid number of parameters"), + PSQLState.SYNTAX_ERROR); } + // move them into the result set + for (int i = 0, j = 0; i < cols; i++, j++) { + // find the next out parameter, the assumption is that the functionReturnType + // array will be initialized with 0 and only out parameters will have values + // other than 0. 0 is the value for java.sql.Types.NULL, which should not + // conflict + while (j < functionReturnType.length && functionReturnType[j] == 0) { + j++; + } + + callResult[j] = rs.getObject(i + 1); + int columnType = rs.getMetaData().getColumnType(i + 1); + + if (columnType != functionReturnType[j]) { + // this is here for the sole purpose of passing the cts + PgCallstatementTypeCompatibility typeCompatibility = new PgCallstatementTypeCompatibility( + columnType, functionReturnType[j]); + if (typeCompatibility.isCompatibilityType()) { + if (callResult[j] != null && typeCompatibility.needConvert()) { + callResult[j] = typeCompatibility.convert(callResult[j]); + } + if (columnType == Types.STRUCT && functionReturnType[j] == Types.OTHER) { + if (callResult[j] != null) { + PGobject pGobject = (PGobject) callResult[j]; + pGobject.setStruct(getcompositeTypeStruct(j + 1)); + } + } + } else { + throw new PSQLException(GT.tr( + "A CallableStatement function was executed and the out parameter {0} was of type {1} however type" + + " {2} was registered.", + i + 1, "java.sql.Types=" + columnType, "java.sql.Types=" + functionReturnType[j]), + PSQLState.DATA_TYPE_MISMATCH); + } + } + } } rs.close(); synchronized (this) { @@ -157,6 +218,18 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme return false; } + /** + * Whether it contains special characters + * + * @param str string used for judgment + * @return contains or does not contain + */ + private boolean isContainSpecialChar(String str) { + return str.contains(Character.toString('"')) || str.contains(Character.toString('\\')) || + str.contains(Character.toString('(')) || str.contains(Character.toString(')')) || + str.contains(Character.toString(',')) || str.contains(Character.toString(' ')); + } + /** * {@inheritDoc} * @@ -214,6 +287,19 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme checkIndex(parameterIndex, false); preparedParameters.registerOutParameter(parameterIndex, sqlType); + + // determine whether to overwrite the original VOID with the oid of the out parameter according to the + // compatibility mode and the state of the guc parameter value + if (isACompatibilityAndOverLoad()) { + Integer oid; + if (sqlTypeToOid.get(sqlType) == null) { + oid = Integer.valueOf(0); + } else { + oid = sqlTypeToOid.get(sqlType); + } + preparedParameters.bindRegisterOutParameter(parameterIndex, oid, isACompatibilityFunction); + } + // functionReturnType contains the user supplied value to check // testReturn contains a modified version to make it easier to // check the getXXX methods.. @@ -229,6 +315,45 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme returnTypeSet = true; } + private static HashMap sqlTypeToOid = new HashMap<>(); + static { + sqlTypeToOid.put(Types.SQLXML, Oid.XML); + sqlTypeToOid.put(Types.INTEGER, Oid.INT4); + sqlTypeToOid.put(Types.TINYINT, Oid.INT1); + sqlTypeToOid.put(Types.SMALLINT, Oid.INT2); + sqlTypeToOid.put(Types.BIGINT, Oid.INT8); + sqlTypeToOid.put(Types.REAL, Oid.FLOAT4); + sqlTypeToOid.put(Types.VARCHAR, Oid.VARCHAR); + sqlTypeToOid.put(Types.DOUBLE, Oid.FLOAT8); + sqlTypeToOid.put(Types.FLOAT, Oid.FLOAT8); + sqlTypeToOid.put(Types.DECIMAL, Oid.NUMERIC); + sqlTypeToOid.put(Types.NUMERIC, Oid.NUMERIC); + sqlTypeToOid.put(Types.CHAR, Oid.BPCHAR); + sqlTypeToOid.put(Types.DATE, Oid.DATE); + sqlTypeToOid.put(Types.TIME, Oid.TIME); + sqlTypeToOid.put(Types.TIMESTAMP, Oid.TIMESTAMP); + sqlTypeToOid.put(Types.TIME_WITH_TIMEZONE, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.TIMESTAMP_WITH_TIMEZONE, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.BOOLEAN, Oid.BOOL); + sqlTypeToOid.put(Types.BIT, Oid.BOOL); + sqlTypeToOid.put(Types.BINARY, Oid.BYTEA); + sqlTypeToOid.put(Types.VARBINARY, Oid.BYTEA); + sqlTypeToOid.put(Types.LONGVARBINARY, Oid.BYTEA); + sqlTypeToOid.put(Types.BLOB, Oid.BLOB); + sqlTypeToOid.put(Types.CLOB, Oid.CLOB); + sqlTypeToOid.put(Types.ARRAY, Oid.VARCHAR_ARRAY); + sqlTypeToOid.put(Types.DISTINCT, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.STRUCT, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.NULL, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.OTHER, Oid.UNSPECIFIED); + sqlTypeToOid.put(Types.LONGVARCHAR, Oid.VARCHAR); + sqlTypeToOid.put(Types.NVARCHAR, Oid.VARCHAR); + sqlTypeToOid.put(Types.LONGNVARCHAR, Oid.VARCHAR); + sqlTypeToOid.put(Types.NCHAR, Oid.CHAR); + sqlTypeToOid.put(Types.REF_CURSOR, Oid.REF_CURSOR); + + } + public boolean wasNull() throws SQLException { if (lastIndex == 0) { throw new PSQLException(GT.tr("wasNull cannot be call before fetching a result."), @@ -495,10 +620,18 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme } public Clob getClob(int i) throws SQLException { - PGClob pgClob = (PGClob) callResult[i-1]; - String str = pgClob.getSubString(1, (int) pgClob.length()); - Clob clob = new PGClob(); - clob.setString(1, str); + Clob clob = null; + if (callResult[i - 1] instanceof PGClob) { + PGClob pgClob = (PGClob) callResult[i - 1]; + String str = pgClob.getSubString(1, (int) pgClob.length()); + clob = new PGClob(); + clob.setString(1, str); + } else { + /* before c20 version, clob type is actually text */ + /* we just use 'getString' method to get Text and set it into clob Object */ + clob = new PGClob(); + clob.setString(1, getString(i)); + } return clob; } @@ -549,9 +682,91 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme return connection.getTimestampUtils().toTimestamp(cal, value); } + private PreparedStatement getCompositeTypeStatement(String typeName) throws SQLException { + // query the column name and oid value of a custom type sub-column. + if (getCompositeTypeStatementSimple == null) { + String sql = "SELECT attname, atttypid " + + "FROM pg_attribute a " + + "JOIN pg_class c ON a.attrelid = c.oid " + + "WHERE c.oid IN ( " + + "SELECT a.typrelid " + + "FROM ( " + + "SELECT pn.nspname || '.' || pt.typname AS typname, pt.typrelid " + + "FROM pg_namespace pn " + + "LEFT JOIN pg_type pt ON pn.oid = pt.typnamespace" + + ") a " + + "WHERE a.typname = ? " + + ") " + + "AND a.attnum > 0 ORDER BY a.attnum"; + getCompositeTypeStatementSimple = connection.prepareStatement(sql); + } + getCompositeTypeStatementSimple.setString(1, typeName); + return getCompositeTypeStatementSimple; + } + + /** + * get custom type structure based on index + * @param index element index + * @return struct of the composite type + */ + private Object[] getcompositeTypeStruct(int index) { + List struct = compositeTypeStructMap.get(index); + Object[] res = new Object[struct.size()]; + for (int i = 0; i < struct.size(); i++) { + res[i] = struct.get(i)[0]; + } + return res; + } + public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException { - throw Driver.notImplemented(this.getClass(), "registerOutParameter(int,int,String)"); + if (sqlType == Types.STRUCT) { + checkClosed(); + if (!isFunction) { + throw new PSQLException( + GT.tr( + "This statement does not declare an OUT parameter. Use '{' ?= call ... '}' to declare one."), + PSQLState.STATEMENT_NOT_ALLOWED_IN_FUNCTION_CALL); + } + checkIndex(parameterIndex, false); + if (compositeTypeMap.containsKey(typeName)) { + compositeTypeStructMap.put(parameterIndex, compositeTypeMap.get(typeName)); + } else { + PreparedStatement compositeTypeStatement = getCompositeTypeStatement(typeName); + // Go through BaseStatement to avoid transaction start. + if (!((BaseStatement) compositeTypeStatement).executeWithFlags(QueryExecutor.QUERY_SUPPRESS_BEGIN)) { + throw new PSQLException(GT.tr("No results were returned by the query."), PSQLState.NO_DATA); + } + ResultSet rs = compositeTypeStatement.getResultSet(); + List compositeType = new ArrayList<>(); + while (rs.next()) { + compositeType.add(new Object[]{rs.getString(1), rs.getInt(2)}); + } + rs.close(); + compositeTypeStructMap.put(parameterIndex, compositeType); + } + + // determine whether to overwrite the original VOID with the oid of the out parameter according to the + // compatibility mode and the state of the guc parameter value + preparedParameters.registerOutParameter(parameterIndex, Types.OTHER); + if (isACompatibilityAndOverLoad()) { + preparedParameters.bindRegisterOutParameter(parameterIndex, connection.getTypeInfo().getPGType(typeName), isACompatibilityFunction); + } + functionReturnType[parameterIndex - 1] = Types.OTHER; + testReturn[parameterIndex - 1] = Types.OTHER; + returnTypeSet = true; + isContainCompositeType = true; + } else { + throw Driver.notImplemented(this.getClass(), "registerOutParameter(int,int,String)"); + } + } + + /** + * whether it is oracle compatibility mode and reload is turned on + * @return true or false + */ + private boolean isACompatibilityAndOverLoad() { + return enableOutparamOveride && ("A".equalsIgnoreCase(compatibilityMode) || "ORA".equalsIgnoreCase(compatibilityMode)); } public RowId getRowId(int parameterIndex) throws SQLException { diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallstatementTypeCompatibility.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallstatementTypeCompatibility.java index 0e2e2378bb4623021d58cdfb6df8a0187cc21ac9..4f3a5ce776ab67b3fe1e5012172b5ed83f7626d0 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallstatementTypeCompatibility.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgCallstatementTypeCompatibility.java @@ -42,6 +42,18 @@ public class PgCallstatementTypeCompatibility { } }; + private static TypeConvert smallint2Tinyint = input -> { + int bit; + int result = 0; + for (int i = 0; i < 8; i++) { + bit = ((int)input >> i) & 0x01; + if (bit == 1) { + result += 1 << i; + } + } + return result; + }; + private static Map typeConvertMap = new ConcurrentHashMap<>(); static { @@ -53,7 +65,9 @@ public class PgCallstatementTypeCompatibility { addConvert(Types.INTEGER, Types.NUMERIC, noneConvert); addConvert(Types.OTHER, -10, noneConvert); addConvert(Types.OTHER, Types.BLOB, noneConvert); + addConvert(Types.BLOB, Types.OTHER, noneConvert); addConvert(Types.REF_CURSOR, Types.OTHER, noneConvert); + addConvert(Types.SMALLINT, Types.TINYINT, smallint2Tinyint); } private int actualType; diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java index 6668a89aeaee1f5463824a4225f29863fd4e6a7c..62b4ca759adccbdfa80bcd0d2a6d986d52597f1a 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java @@ -202,7 +202,7 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement { sqlTypeToOid.put(Types.VARBINARY, Oid.BYTEA); sqlTypeToOid.put(Types.LONGVARBINARY, Oid.BYTEA); sqlTypeToOid.put(Types.BLOB, Oid.BLOB); - sqlTypeToOid.put(Types.CLOB, Oid.OID); + sqlTypeToOid.put(Types.CLOB, Oid.CLOB); sqlTypeToOid.put(Types.ARRAY, Oid.UNSPECIFIED); sqlTypeToOid.put(Types.DISTINCT, Oid.UNSPECIFIED); sqlTypeToOid.put(Types.STRUCT, Oid.UNSPECIFIED); diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java index 9d2ccb8e50ef7ccda1d8f2698d4360d613a92e4e..599017673b45f76312b2b4e4782c6fc0f90289b9 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java @@ -2500,8 +2500,11 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS // If the data is already binary then just return it return this_row[columnIndex - 1]; } - if (fields[columnIndex - 1].getOID() == Oid.BYTEA) { + int oid = fields[columnIndex - 1].getOID(); + if (oid == Oid.BYTEA) { return trimBytes(columnIndex, PGbytea.toBytes(this_row[columnIndex - 1])); + } else if (oid == Oid.BLOB) { + return toBytes(getString(columnIndex)); } else { return trimBytes(columnIndex, this_row[columnIndex - 1]); } @@ -2818,7 +2821,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS s = "-" + s.substring(2); } - return s; + return s.replace(",", ""); } protected String getPGType(int column) throws SQLException { diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java index b95cc63cb921675c0035fa0657120b54893dc43c..7abe1828075a343ed755a6a5c0aa705a920cbd0a 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgStatement.java @@ -152,7 +152,7 @@ public class PgStatement implements Statement, BaseStatement { if (c.getClientLogic() != null) { this.statementName = c.getClientLogic().getStatementName(); - } + } } public ResultSet createResultSet(Query originalQuery, Field[] fields, List tuples, @@ -419,7 +419,7 @@ public class PgStatement implements Statement, BaseStatement { checkClosed(); if (null == x) { - queryParameters.setNull(parameterIndex, Oid.BYTEA); + queryParameters.setNull(parameterIndex, customOid); return; } byte[] copy = new byte[x.length]; @@ -618,11 +618,11 @@ public class PgStatement implements Statement, BaseStatement { } catch(ClientLogicException e) { if (e.isParsingError()) { - /* + /* * we should not block bad queries to be sent to the server * PgConnection.isValid is based on error that is not parsed correctly */ - LOGGER.debug("pre query failed for parsing error, moving on"); + LOGGER.debug("pre query failed for parsing error, moving on"); } else { LOGGER.debug("Failed running runQueryPreProcess on executeInternal " + e.getErrorCode() + ":" + e.getErrorText()); throw new SQLException(e.getErrorText()); @@ -1087,6 +1087,14 @@ public class PgStatement implements Statement, BaseStatement { if (batchStatements == null || batchStatements.isEmpty()) { return new int[0]; } + + if (this.connection instanceof PgConnection) { + PgConnection con = (PgConnection) this.connection; + if (con.isBatchInsert() && batchStatements.get(0).getSqlCommand().isBatchedReWriteCompatible()) { + throw new PSQLException(GT.tr("batchMode and reWriteBatchedInserts can not both set true!"), + PSQLState.NOT_IMPLEMENTED); + } + } return internalExecuteBatch().getUpdateCount(); } diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java b/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java index e5b8e69a545ca3f31b1256cf1f2866831e78c559..93dfbb77eb3f73d5d6fd468ef90658e9f117c092 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/TypeInfoCache.java @@ -92,6 +92,7 @@ public class TypeInfoCache implements TypeInfo { {"point", Oid.POINT, Types.OTHER, "org.postgresql.geometric.PGpoint", Oid.POINT_ARRAY}, {"blob", Oid.BLOB, Types.BLOB, "org.postgresql.util.PGobject", -1}, {"clob", Oid.CLOB, Types.CLOB, "org.postgresql.util.PGobject", -1}, + {"nvarchar2", Oid.NVARCHAR2, Types.VARCHAR, "java.lang.String", Oid.NVARCHAR2_ARRAY}, {"refcursor", Oid.REF_CURSOR, Types.REF_CURSOR, "java.sql.ResultSet", Oid.REF_CURSOR_ARRAY} }; @@ -241,7 +242,7 @@ public class TypeInfoCache implements TypeInfo { private PreparedStatement getOidStatement(String pgTypeName) throws SQLException { if (_getOidStatementSimple == null) { String sql; - sql = "SELECT oid FROM pg_catalog.pg_type WHERE typname = ?"; + sql = "SELECT oid, typname FROM pg_catalog.pg_type WHERE typname = ?"; _getOidStatementSimple = _conn.prepareStatement(sql); } _getOidStatementSimple.setString(1, pgTypeName); diff --git a/pgjdbc/src/main/java/org/postgresql/log/Slf4JLogger.java b/pgjdbc/src/main/java/org/postgresql/log/Slf4JLogger.java index 8480157616f39895afffadaa5f64555746a58ddb..d30b0df7101c1da1a1ffb5f10d0f18b08a92d459 100644 --- a/pgjdbc/src/main/java/org/postgresql/log/Slf4JLogger.java +++ b/pgjdbc/src/main/java/org/postgresql/log/Slf4JLogger.java @@ -1,7 +1,7 @@ package org.postgresql.log; -import com.huawei.shade.org.slf4j.Logger; -import com.huawei.shade.org.slf4j.LoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Slf4JLogger implements Log { private Logger logger; diff --git a/pgjdbc/src/main/java/org/postgresql/log/Tracer.java b/pgjdbc/src/main/java/org/postgresql/log/Tracer.java new file mode 100644 index 0000000000000000000000000000000000000000..ce3805bc5ff2228675b6250e31e8304b12442f62 --- /dev/null +++ b/pgjdbc/src/main/java/org/postgresql/log/Tracer.java @@ -0,0 +1,14 @@ +package org.postgresql.log; + +/** + * Tracker interface class. + * + */ +public interface Tracer { + /** + * Used to obtain the globally unique trace id. + * + * @return trace id. + */ + String getTraceId(); +} diff --git a/pgjdbc/src/main/java/org/postgresql/ssl/LibPQFactory.java b/pgjdbc/src/main/java/org/postgresql/ssl/LibPQFactory.java index 9bef6d448f575d9af14215b18d4dabb97be02087..5a683b4ac8cba7927d74c3e398130f4aa0af6892 100644 --- a/pgjdbc/src/main/java/org/postgresql/ssl/LibPQFactory.java +++ b/pgjdbc/src/main/java/org/postgresql/ssl/LibPQFactory.java @@ -81,7 +81,7 @@ public class LibPQFactory extends WrappedFactory { String sslpasswordcallback = PGProperty.SSL_PASSWORD_CALLBACK.get(info); if (sslpasswordcallback != null) { try { - cbh = (CallbackHandler) ObjectFactory.instantiate(sslpasswordcallback, info, false, null); + cbh = ObjectFactory.instantiate(CallbackHandler.class, sslpasswordcallback, info, false, null); } catch (Exception e) { throw new PSQLException( GT.tr("The password callback class provided {0} could not be instantiated.", diff --git a/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java b/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java index 646532271ea32985edd102c424d863983d9b7c77..b0cef4a1a47567073f85fda29abd49cbe9bea585 100644 --- a/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java +++ b/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java @@ -75,7 +75,7 @@ public class MakeSSL extends ObjectFactory { sslhostnameverifier = "PgjdbcHostnameVerifier"; } else { try { - hvn = (HostnameVerifier) instantiate(sslhostnameverifier, info, false, null); + hvn = instantiate(HostnameVerifier.class, sslhostnameverifier, info, false, null); } catch (Exception e) { throw new PSQLException( GT.tr("The HostnameVerifier class provided {0} could not be instantiated.", diff --git a/pgjdbc/src/main/java/org/postgresql/util/MD5Digest.java b/pgjdbc/src/main/java/org/postgresql/util/MD5Digest.java index 99537e67da209cfaa8cb6f741838ee93a4bff760..cce694934160d8991508d5041b7cc698a94f2f9d 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/MD5Digest.java +++ b/pgjdbc/src/main/java/org/postgresql/util/MD5Digest.java @@ -299,7 +299,7 @@ public class MD5Digest { if (isSha256) { storedKey = sha256(clientKey); } else { - storedKey = sm3(clientKey); + storedKey = sm3(clientKey); } byte[] tokenbyte = hexStringToBytes(token); byte[] client_signature = getKeyFromHmac(server_key, tokenbyte); diff --git a/pgjdbc/src/main/java/org/postgresql/util/ObjectFactory.java b/pgjdbc/src/main/java/org/postgresql/util/ObjectFactory.java index 273ac6d6119f8787d999fc65466ae118cd65119c..38c3df084f812cdeaa71953f14d117b618406792 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/ObjectFactory.java +++ b/pgjdbc/src/main/java/org/postgresql/util/ObjectFactory.java @@ -15,49 +15,54 @@ import java.util.Properties; */ public class ObjectFactory { - /** - * Instantiates a class using the appropriate constructor. If a constructor with a single - * Propertiesparameter exists, it is used. Otherwise, if tryString is true a constructor with a - * single String argument is searched if it fails, or tryString is true a no argument constructor - * is tried. - * - * @param classname name of the class to instantiate - * @param info parameter to pass as Properties - * @param tryString weather to look for a single String argument constructor - * @param stringarg parameter to pass as String - * @return the instantiated class - * @throws ClassNotFoundException if something goes wrong - * @throws SecurityException if something goes wrong - * @throws NoSuchMethodException if something goes wrong - * @throws IllegalArgumentException if something goes wrong - * @throws InstantiationException if something goes wrong - * @throws IllegalAccessException if something goes wrong - * @throws InvocationTargetException if something goes wrong - */ - public static Object instantiate(String classname, Properties info, boolean tryString, - String stringarg) throws ClassNotFoundException, SecurityException, NoSuchMethodException, - IllegalArgumentException, InstantiationException, IllegalAccessException, - InvocationTargetException { - Object[] args = {info}; - Constructor ctor = null; - Class cls = Class.forName(classname); - try { - ctor = cls.getConstructor(Properties.class); - } catch (NoSuchMethodException nsme) { - if (tryString) { + /** + * + * Instantiates a class using the appropriate constructor. If a constructor with a single + * Propertiesparameter exists, it is used. Otherwise, if tryString is true a constructor with a + * single String argument is searched if it fails, or tryString is true a no argument constructor + * is tried. + * + * @param expectedClass expected to inherit from the parent class + * @param classname classname name of the class to instantiate + * @param info parameter to pass as Properties + * @param tryString weather to look for a single String argument constructor + * @param stringarg parameter to pass as String + * @param generic class + * @return the instantiated class + * @throws ClassNotFoundException if something goes wrong + * @throws SecurityException if something goes wrong + * @throws NoSuchMethodException if something goes wrong + * @throws IllegalArgumentException if something goes wrong + * @throws InstantiationException if something goes wrong + * @throws IllegalAccessException if something goes wrong + * @throws InvocationTargetException if something goes wrong + */ + public static T instantiate(Class expectedClass, String classname, Properties info, + boolean tryString, String stringarg) throws ClassNotFoundException, + SecurityException, + NoSuchMethodException, + IllegalArgumentException, InstantiationException, IllegalAccessException, + InvocationTargetException { + Object[] args = {info}; + Constructor ctor = null; + Class cls = Class.forName(classname).asSubclass(expectedClass); try { - ctor = cls.getConstructor(String.class); - args = new String[]{stringarg}; - } catch (NoSuchMethodException nsme2) { - tryString = false; + ctor = cls.getConstructor(Properties.class); + } catch (NoSuchMethodException nsme) { + if (tryString) { + try { + ctor = cls.getConstructor(String.class); + args = new String[]{stringarg}; + } catch (NoSuchMethodException nsme2) { + tryString = false; + } + } + if (!tryString) { + ctor = cls.getConstructor((Class[]) null); + args = null; + } } - } - if (!tryString) { - ctor = cls.getConstructor((Class[]) null); - args = null; - } + return ctor.newInstance(args); } - return ctor.newInstance(args); - } } diff --git a/pgjdbc/src/main/java/org/postgresql/util/PGobject.java b/pgjdbc/src/main/java/org/postgresql/util/PGobject.java index 2686cb2e47ca75c3f8dfdbc86559989fc7efb072..ef0f3ebe48bdc3f2be4b098a83fd9bae78d3ea16 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/PGobject.java +++ b/pgjdbc/src/main/java/org/postgresql/util/PGobject.java @@ -14,100 +14,196 @@ import java.sql.SQLException; * JDBC Standards. */ public class PGobject implements Serializable, Cloneable { - protected String type; - protected String value; - - /** - * This is called by org.postgresql.Connection.getObject() to create the object. - */ - public PGobject() { - } - - /** - *

This method sets the type of this object.

- * - *

It should not be extended by subclasses, hence it is final

- * - * @param type a string describing the type of the object - */ - public final void setType(String type) { - this.type = type; - } - - /** - * This method sets the value of this object. It must be overridden. - * - * @param value a string representation of the value of the object - * @throws SQLException thrown if value is invalid for this type - */ - public void setValue(String value) throws SQLException { - this.value = value; - } - - /** - * As this cannot change during the life of the object, it's final. - * - * @return the type name of this object - */ - public final String getType() { - return type; - } - - /** - * This must be overidden, to return the value of the object, in the form required by - * org.postgresql. - * - * @return the value of this object - */ - public String getValue() { - return value; - } - - /** - * This must be overidden to allow comparisons of objects. - * - * @param obj Object to compare with - * @return true if the two boxes are identical - */ - public boolean equals(Object obj) { - if (obj instanceof PGobject) { - final Object otherValue = ((PGobject) obj).getValue(); - - if (otherValue == null) { - return getValue() == null; - } - return otherValue.equals(getValue()); + protected String type; + protected String value; + + /** + * when the object is a custom type is used to save its structure + */ + protected Object[] struct; + + /** + * Cache result + */ + private String[] arrayValue; + + /** + * This is called by org.postgresql.Connection.getObject() to create the object. + */ + public PGobject() { + } + + /** + *

This method sets the type of this object.

+ * + *

It should not be extended by subclasses, hence it is final

+ * + * @param type a string describing the type of the object + */ + public final void setType(String type) { + this.type = type; + } + + /** + * This method sets the value of this object. It must be overridden. + * + * @param value a string representation of the value of the object + * @throws SQLException thrown if value is invalid for this type + */ + public void setValue(String value) throws SQLException { + this.value = value; + } + + /** + * As this cannot change during the life of the object, it's final. + * + * @return the type name of this object + */ + public final String getType() { + return type; + } + + /** + * This must be overidden, to return the value of the object, in the form required by + * org.postgresql. + * + * @return the value of this object + */ + public String getValue() { + return value; + } + + /** + *

This method sets the struct of this object.

+ *

It should not be extended by subclasses, hence it is final

+ * + * @param struct struct a Object[] describing the struct of the object + */ + public final void setStruct(Object[] struct) { + this.struct = struct; + } + + /** + * As this cannot change during the life of the object, it's final. + * + * @return the struct of this object + */ + public final Object[] getStruct() { + return struct; + } + + /** + * parse string to array + * + * @return custom type array structure value + */ + public String[] getArrayValue() { + if (arrayValue != null) { + return arrayValue; + } + if (struct != null && struct.length > 0 && this.value.length() > 2) { + arrayValue = new String[struct.length]; + // remove the parentheses. + char[] chars = this.value.toCharArray(); + int noBeginAndEndBracketLen = chars.length - 1; + int begin = 1; + int end = 1; + int index = 0; + for (int i = 1; i < noBeginAndEndBracketLen; i++) { + // If the character starts with a double quote character, this value contains the following special + // characters , or " or ( or ) or \ or blank. + if (chars[i] == '"') { + while (i + 2 <= noBeginAndEndBracketLen) { + if (chars[i + 1] == '"') { + if ((i + 2 == noBeginAndEndBracketLen) || (chars[i + 2] == ',')) { + i = i + 2; + end = i; + arrayValue[index] = delimitedCompositeTypeValue(begin, end, this.value); + index++; + begin = end + 1; + break; + } else if (chars[i + 2] != '"') { // String format error,return undisassembled value. + arrayValue = new String[]{this.value}; + return new String[]{this.value}; + } + i = i + 2; + } else { + i++; + } + } + } else if (chars[i] == ',') { // If it is a comma, intercept the initial position to the current + // position. + end = i; + arrayValue[index] = delimitedCompositeTypeValue(begin, end, this.value); + index++; + begin = end + 1; + } + } + if (end != noBeginAndEndBracketLen) { + arrayValue[index] = delimitedCompositeTypeValue(begin, noBeginAndEndBracketLen, this.value); + } + } else { + arrayValue = new String[]{this.value}; + } + return arrayValue; + } + + /** + * @param begin start index + * @param end finish index + * @param originalChar raw data + * @return specify the subscript data + */ + private String delimitedCompositeTypeValue(int begin, int end, String originalChar) { + String attribute = originalChar.substring(begin, end); + return (attribute != null && attribute.length() > 0) ? attribute : null; + } + + /** + * This must be overidden to allow comparisons of objects. + * + * @param obj Object to compare with + * @return true if the two boxes are identical + */ + public boolean equals(Object obj) { + if (obj instanceof PGobject) { + final Object otherValue = ((PGobject) obj).getValue(); + + if (otherValue == null) { + return getValue() == null; + } + return otherValue.equals(getValue()); + } + return false; + } + + /** + * This must be overidden to allow the object to be cloned. + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + /** + * This is defined here, so user code need not overide it. + * + * @return the value of this object, in the syntax expected by org.postgresql + */ + public String toString() { + return getValue(); + } + + /** + * Compute hash. As equals() use only value. Return the same hash for the same value. + * + * @return Value hashcode, 0 if value is null {@link java.util.Objects#hashCode(Object)} + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } - return false; - } - - /** - * This must be overidden to allow the object to be cloned. - */ - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - /** - * This is defined here, so user code need not overide it. - * - * @return the value of this object, in the syntax expected by org.postgresql - */ - public String toString() { - return getValue(); - } - - /** - * Compute hash. As equals() use only value. Return the same hash for the same value. - * - * @return Value hashcode, 0 if value is null {@link java.util.Objects#hashCode(Object)} - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - - } } diff --git a/pgjdbc/src/main/java/org/postgresql/util/PSQLException.java b/pgjdbc/src/main/java/org/postgresql/util/PSQLException.java index f81fb089ed097b49489ccc459dc317d0fa322bb3..3fd74af47c42d9b9296d2856d737e1278185f1bb 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/PSQLException.java +++ b/pgjdbc/src/main/java/org/postgresql/util/PSQLException.java @@ -32,7 +32,8 @@ public class PSQLException extends SQLException { } public PSQLException(ServerErrorMessage serverError) { - super(serverError.toString(), serverError.getSQLState(), Integer.parseInt(serverError.getERRORCODE())); + super(serverError.toString(), serverError.getSQLState(), + (serverError.getERRORCODE() == null) ? 0 : Integer.parseInt(serverError.getERRORCODE())); _serverError = serverError; } diff --git a/pgjdbc/src/main/java/org/postgresql/util/ServerErrorMessage.java b/pgjdbc/src/main/java/org/postgresql/util/ServerErrorMessage.java index 5de39347de3254c658c72c34bc586ce34b6f5514..b4b08215b004757fbbc2a1f8fcfcf7adf3b009c1 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/ServerErrorMessage.java +++ b/pgjdbc/src/main/java/org/postgresql/util/ServerErrorMessage.java @@ -150,11 +150,7 @@ public class ServerErrorMessage implements Serializable { // is included. StringBuilder l_totalMessage = new StringBuilder(); - String l_message = m_mesgParts.get(SOCKET_ADDRESS); - if (l_message != null) { - l_totalMessage.append("[" + l_message + "] "); - } - l_message = m_mesgParts.get(SEVERITY); + String l_message = m_mesgParts.get(SEVERITY); if (l_message != null) { l_totalMessage.append(l_message).append(": "); } diff --git a/pgjdbc/src/test/java/org/postgresql/core/OidToStringTest.java b/pgjdbc/src/test/java/org/postgresql/core/OidToStringTest.java index 5f4586fa705b928fdacea56de90702bc1ed9bfd4..bfc782e93a5f0c91e2483a1754860c07d7f02add 100644 --- a/pgjdbc/src/test/java/org/postgresql/core/OidToStringTest.java +++ b/pgjdbc/src/test/java/org/postgresql/core/OidToStringTest.java @@ -5,8 +5,6 @@ package org.postgresql.core; -import org.postgresql.util.PSQLException; - import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,22 +14,18 @@ import java.util.Arrays; @RunWith(Parameterized.class) public class OidToStringTest { - @Parameterized.Parameter(0) - public int value; - @Parameterized.Parameter(1) - public String expected; + @Parameterized.Parameter(0) + public int value; + @Parameterized.Parameter(1) + public String expected; - @Parameterized.Parameters(name = "expected={1}, value={0}") - public static Iterable data() { - return Arrays.asList(new Object[][]{ - {142, "XML"}, - {0, "UNSPECIFIED"}, - {-235, ""}, - }); - } + @Parameterized.Parameters(name = "expected={1}, value={0}") + public static Iterable data() { + return Arrays.asList(OidValueOfTest.types); + } - @Test - public void run() throws PSQLException { - Assert.assertEquals(expected, Oid.toString(value)); - } + @Test + public void run() { + Assert.assertEquals(expected, Oid.toString(value)); + } } diff --git a/pgjdbc/src/test/java/org/postgresql/core/OidValueOfTest.java b/pgjdbc/src/test/java/org/postgresql/core/OidValueOfTest.java index 110af68d77016ec037e97b06f200f17db23a4f06..88b7acc93eeeeaa79bcc29a570ab9efb971987cf 100644 --- a/pgjdbc/src/test/java/org/postgresql/core/OidValueOfTest.java +++ b/pgjdbc/src/test/java/org/postgresql/core/OidValueOfTest.java @@ -16,23 +16,89 @@ import java.util.Arrays; @RunWith(Parameterized.class) public class OidValueOfTest { - @Parameterized.Parameter(0) - public int expected; - @Parameterized.Parameter(1) - public String value; - - @Parameterized.Parameters(name = "expected={0}, value={1}") - public static Iterable data() { - return Arrays.asList(new Object[][]{ - {25, "TEXT"}, - {0, "UNSPECIFIED"}, - {199, "JSON_ARRAY"}, - {100, "100"}, - }); - } - - @Test - public void run() throws PSQLException { - Assert.assertEquals(expected, Oid.valueOf(value)); - } + @Parameterized.Parameter(0) + public int expected; + @Parameterized.Parameter(1) + public String value; + + public static Object[][] types = new Object[][]{ + {0, "UNSPECIFIED"}, + {5545,"INT1"}, + {5546,"INT1_ARRAY"}, + {21,"INT2"}, + {1005,"INT2_ARRAY"}, + {23,"INT4"}, + {1007,"INT4_ARRAY"}, + {20,"INT8"}, + {1016,"INT8_ARRAY"}, + {25, "TEXT"}, + {1009,"TEXT_ARRAY"}, + {1700,"NUMERIC"}, + {1231,"NUMERIC_ARRAY"}, + {700,"FLOAT4"}, + {1021,"FLOAT4_ARRAY"}, + {701,"FLOAT8"}, + {1022,"FLOAT8_ARRAY"}, + {16,"BOOL"}, + {1000,"BOOL_ARRAY"}, + {1082,"DATE"}, + {1182,"DATE_ARRAY"}, + {1083,"TIME"}, + {1183,"TIME_ARRAY"}, + {1266,"TIMETZ"}, + {1270,"TIMETZ_ARRAY"}, + {1114,"TIMESTAMP"}, + {1115,"TIMESTAMP_ARRAY"}, + {1184,"TIMESTAMPTZ"}, + {1185,"TIMESTAMPTZ_ARRAY"}, + {9003,"SMALLDATETIME"}, + {9005,"SMALLDATETIME_ARRAY"}, + {17,"BYTEA"}, + {1001,"BYTEA_ARRAY"}, + {1043,"VARCHAR"}, + {1015,"VARCHAR_ARRAY"}, + {26,"OID"}, + {1028,"OID_ARRAY"}, + {1042,"BPCHAR"}, + {1014,"BPCHAR_ARRAY"}, + {790,"MONEY"}, + {791,"MONEY_ARRAY"}, + {19,"NAME"}, + {1003,"NAME_ARRAY"}, + {1560,"BIT"}, + {1561,"BIT_ARRAY"}, + {2278,"VOID"}, + {1186,"INTERVAL"}, + {1187,"INTERVAL_ARRAY"}, + {18,"CHAR"}, + {1002,"CHAR_ARRAY"}, + {1562,"VARBIT"}, + {1563,"VARBIT_ARRAY"}, + {2950,"UUID"}, + {2951,"UUID_ARRAY"}, + {142,"XML"}, + {143,"XML_ARRAY"}, + {600,"POINT"}, + {1017,"POINT_ARRAY"}, + {603,"BOX"}, + {3807,"JSONB_ARRAY"}, + {114,"JSON"}, + {199,"JSON_ARRAY"}, + {1790,"REF_CURSOR"}, + {2201, "REF_CURSOR_ARRAY"}, + {88, "BLOB"}, + {90, "CLOB"}, + {3969, "NVARCHAR2"}, + {3968, "NVARCHAR2_ARRAY"}, + }; + + @Parameterized.Parameters(name = "expected={0}, value={1}") + public static Iterable data() { + return Arrays.asList(types); + } + + @Test + public void run() throws PSQLException { + Assert.assertEquals(expected, Oid.valueOf(value)); + } } diff --git a/pgjdbc/src/test/java/org/postgresql/replication/ReplicationConnectionTest.java b/pgjdbc/src/test/java/org/postgresql/replication/ReplicationConnectionTest.java index 6c98ca0d352d98e4ab40e0b63027a056d114fe55..01cd0851f631744c7de0ae8f0f35c72fc79eb458 100644 --- a/pgjdbc/src/test/java/org/postgresql/replication/ReplicationConnectionTest.java +++ b/pgjdbc/src/test/java/org/postgresql/replication/ReplicationConnectionTest.java @@ -52,25 +52,6 @@ public class ReplicationConnectionTest { ); } - @Test - public void testConnectionNotValidWhenSessionTerminated() throws Exception { - int backendId = ((PgConnection) replConnection).getQueryExecutor().getBackendPID(); - - Connection sqlConnection = TestUtil.openDB(); - - Statement terminateStatement = sqlConnection.createStatement(); - terminateStatement.execute("SELECT pg_terminate_backend(" + backendId + ")"); - terminateStatement.close(); - sqlConnection.close(); - - boolean result = replConnection.isValid(3); - - assertThat("When postgresql terminate session with replication connection, " - + "isValid methos should return false, because next query on this connection will fail", - result, equalTo(false) - ); - } - @Test public void testReplicationCommandResultSetAccessByIndex() throws Exception { Statement statement = replConnection.createStatement(); diff --git a/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java b/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java index b381602533db8891d71d070cc55b53d864d3b3d6..01751f97d939994bf42c284ebe3073425bc236bd 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java +++ b/pgjdbc/src/test/java/org/postgresql/test/TestUtil.java @@ -923,4 +923,10 @@ public class TestUtil { throw new TimeoutException("Wait stop replication slot " + timeInWait + " timeout occurs"); } } + + public static boolean execute(String sql, Connection conn) throws SQLException { + try (Statement st = conn.createStatement()) { + return st.execute(sql); + } + } } diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/BeginEndTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/BeginEndTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2c9805b9ad0f614300ecbc416dccbe7d49ccdfa5 --- /dev/null +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/BeginEndTest.java @@ -0,0 +1,428 @@ +package org.postgresql.test.jdbc2; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.postgresql.test.TestUtil; + +import java.sql.CallableStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.junit.Assert.assertEquals; + +public class BeginEndTest extends BaseTest4 { + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @After + public void tearDown() throws SQLException { + + } + + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:存储过程中有end if,后面语句中有空格加/组合 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace procedure proc_test(p1 int,p2 int ,p3 VARCHAR2(5) ,p4 out int) as\n" + + "\n" + + "begin\n" + + " p4 := 0;\n" + + " if p3 = '+' then \n" + + " p4 := p1 + p2;\n" + + " end if;\n" + + " \n" + + " if p3 = '-' then \n" + + " p4 := p1 - p2;\n" + + " end if;\n" + + " \n" + + " if p3 = '*' then \n" + + " p4 := p1 * p2;\n" + + " end if;\n" + + " if p3 = ' /' then \n" + + " p4 := p1 / p2;\n" + + " end if; " + "\n" + + " \n" + + "end;\n" + + "/"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:end if 中间有换行,结尾处end有注释的场景 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase2() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace procedure proc_test(num1 int,num2 int,p3 VARCHAR2(5),num3 out int ) as\n" + + "\n" + + "begin\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end \n" + "" + + " if;\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end if;\n" + + " if p3 = '/' then \n" + + " num3 := num1\n" + + " / num2+1;" + "\n" + + " end if;" + "\n" + + "end /*ffff*/ ----- \n " + + " /"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:end if 中间有换行,结尾处end有注释的场景 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase3() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace procedure proc_test(num1 int,num2 int,p3 VARCHAR2(5),num3 out int ) as\n" + + "\n" + + "begin\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end \n" + "" + + " if;\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end if;\n" + + " if p3 = '/' then \n" + + " num3 := num1" + + " / num2+1;" + "\n" + + " end if;" + "\n" + + "end /" + + " " + "create or replace procedure proc_test(num1 int,num2 int,p3 VARCHAR2(5),num3 out int ) as\n" + + "\n" + + "begin\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end " + "" + + " if;\n" + + " if p3 = '*' then \n" + + " num3 := num1 * num2;\n" + + " end if;\n" + + " if p3 = '/' then \n" + + " num3 := num1" + + "/ num2+1;" + "\n" + + " end if;" + "\n" + + "end\t /*ffff*/ \n " + + " "); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:执行两个带$$language的语句 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase4() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("CREATE OR REPLACE FUNCTION compute(i int, out result_1 bigint)\n" + + "returns SETOF RECORD\n" + + "as $$\n" + + "begin\n" + + " result_1 = i + 1;\n" + + "return next;\n" + + " end " + + "$$language plpgsql;\n" + + " /" + "CREATE OR REPLACE FUNCTION compute(i int, out result_1 bigint)\n" + + "returns SETOF RECORD\n" + + "as $$\n" + + "begin\n" + + " result_1 = i + 1;\n" + + "return next;\n" + + " end " + + "$$ language plpgsql;\n"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:case和end的场景 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase5() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("select case when id =0 then '结果为0' when id=1 then '结果为1' end from company"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:创建匿名块 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase6() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("DECLARE \n" + + " my_var VARCHAR2(30); \n" + + "BEGIN \n" + + " my_var :='world'; \n" + + " dbe_output.print_line('hello'||my_var); \n" + + "END \n" + + " /"); + stmt.execute("BEGIN\n" + + " dbe_output.print_line('hello world!'); \n" + + "END; \n" + + "/"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:end $$结尾 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase7() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("CREATE OR REPLACE FUNCTION func_return returns void\n" + + "language plpgsql\n" + + "AS $$\n" + + "DECLARE\n" + + "v_num INTEGER := 1;\n" + + "BEGIN\n" + + "dbe_output.print_line(v_num);\n" + + "RETURN; --返回语句\n" + + "END $$ /\n"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:创建函数 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase8() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace function testVarchar()\n" + + "return nvarchar2\n" + + "as\n" + + "declare\n" + + "v_pare nvarchar2;\n" + + "begin\n" + + "select 'nvarchar2' into v_pare;\n" + + "return v_pare;\n" + + "end;"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:存储过程中间包含end,但是语句中没有跟着 / + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase9() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace procedure proc_test1() as\n" + + "\n" + + "begin\n" + + "select 2 as end;\n" + + "end \n " + + " /" + "create or replace procedure proc_test1() as\n" + + "\n" + + "begin\n" + + "select 1 - 2;" + + "end \n " + + " /"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:存储过程中间包含end,但是语句中的/,前面没有空格和回车 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase10() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("DECLARE \n" + + " my_var VARCHAR2(30); \n" + + "BEGIN \n" + + " my_var :='world'; \n" + + " dbe_output.print_line('hello'||my_var); \n" + + "END \n" + + " /" + + ""); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:创建空包场景 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase12() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("create or replace package cnt6\n" + + "as\n" + + "count_sum constant number := 1;\n" + + "end cnt6;\n" + + "/"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /***************************************************************** + * 描述:目前可用支持的使用场景 + * 被测对象:Parser + * 输入:无 + * 测试场景:存储过程中间包含end加括号的组合 + * 期望输出:存储过程创建成功 + ******************************************************************/ + @Test + public void testCase11() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + stmt.execute("CREATE OR REPLACE PROCEDURE array_proc\n" + + "AS\n" + + "TYPE ARRAY_INTEGER IS VARRAY(1024) OF INTEGER;--定义数组类型\n" + + "ARRINT ARRAY_INTEGER := ARRAY_INTEGER(); --声明数组类型的变量\n" + + "BEGIN \n" + + "ARRINT.extend(10);\n" + + "FOR I IN 1..10 LOOP\n" + + "ARRINT(I) := I;\n" + + "END LOOP;\n" + + "DBE_OUTPUT.PRINT_LINE(ARRINT.COUNT);\n" + + "DBE_OUTPUT.PRINT_LINE(ARRINT(1));\n" + + "DBE_OUTPUT.PRINT_LINE(ARRINT(10));\n" + + "DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.FIRST));\n" + + "DBE_OUTPUT.PRINT_LINE(ARRINT(ARRINT.last));\n" + + "END;\n" + + "/"); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /***************************************************************** + * 描述:目前不可用场景,在存储过程内部构建出了end关键字。 + * 被测对象:Parser + * 输入:无 + * 测试场景:存储过程中间包含end,但是语句中的/,前面有空格或回车 + * 期望输出:存储过程创建失败 + ******************************************************************/ + @Test + public void testFailCase() throws SQLException { + Statement stmt = con.createStatement(); + CallableStatement cmt = null; + try { + try { + stmt.execute("create or replace procedure proc_test(num1 int,num2 int,p3 VARCHAR2(5),num3 out int ) as\n" + + "\n" + + "begin\n" + + "select 1 as " + + "end;\n" + + "select 1 /1;\n" + + "end\n " + + "/"); + } catch (SQLException e) { + System.out.println(e.getMessage()); + } + try { + stmt.execute("create or replace procedure proc_test(num1 int,num2 int,p3 VARCHAR2(5),num3 out int ) as\n" + + "\n" + + "begin\n" + + "select 1 as " + + "end;\n" + + "select 1\n/1;\n" + + "end\n " + + "/"); + } catch (SQLException e) { + System.out.println(e.getMessage()); + } + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } +} diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ClobBatchTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ClobBatchTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b59ede5e288e1b81aa6d805e39eaf7cf1d0d04f4 --- /dev/null +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ClobBatchTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.test.jdbc2; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.postgresql.test.TestUtil; + +import javax.sql.rowset.serial.SerialClob; +import java.io.IOException; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Some simple tests based on problems reported by users. Hopefully these will help prevent previous + * problems from re-occurring ;-) + */ +public class ClobBatchTest { + private static final int LOOP = 0; // LargeObject API using loop + private static final int NATIVE_STREAM = 1; // LargeObject API using OutputStream + + private Connection con; + + @Before + public void setUp() throws Exception { + Properties props = new Properties(); + // blob and clob can exchange must set string is not varchar! +// props.setProperty(PGProperty.STRING_TYPE.getName(), "unspecified"); + con = TestUtil.openDB(props); + TestUtil.createTable(con, "testclob", "id int,lo clob"); + con.setAutoCommit(false); + } + + @After + public void tearDown() throws Exception { + con.setAutoCommit(true); + TestUtil.dropTable(con, "testclob"); + TestUtil.closeDB(con); + } + + @Test + public void testNormalInsert() throws SQLException, IOException { + String sql = "insert into testclob (id, lo) values " + " (?, ?)"; + Clob data = new SerialClob("abcd".toCharArray()); + int id = 0; + try (PreparedStatement ps = con.prepareStatement(sql)) { + ps.setInt(1, id); + ps.setClob(2, data); + ps.execute(); + } + + String query = "select id, lo from testclob where id = 0"; + try (Statement st = con.createStatement()) { + try (ResultSet rs = st.executeQuery(query)) { + assertTrue(rs.next()); + int id1 = rs.getInt(1); + assertEquals(id, id1); + Clob data1 = rs.getClob(2); + assertEquals(data.getSubString(1, 4), data1.getSubString(1, 4)); + } + } + } + + @Test + public void testSetNull() throws Exception { + PreparedStatement pstmt = con.prepareStatement("INSERT INTO testclob(lo) VALUES (?)"); + + pstmt.setClob(1, (Clob) null); + pstmt.executeUpdate(); + + pstmt.setNull(1, Types.CLOB); + pstmt.executeUpdate(); + + pstmt.setObject(1, null, Types.CLOB); + pstmt.executeUpdate(); + + pstmt.setObject(1, ""); + pstmt.executeUpdate(); + } + + @Test + public void testInsertNullBatch() throws SQLException { + String sql = "insert into testclob (id, lo) values " + " (?, ?)"; + Object[] inputs = {null, ""}; + try (PreparedStatement ps = con.prepareStatement(sql)) { + ps.setInt(1, 0); + ps.setObject(2, null, Types.CLOB); + ps.addBatch(); + ps.setInt(1, 1); + ps.setObject(2, ""); + ps.addBatch(); + ps.executeBatch(); + } + + String query = "select id, lo from testclob"; + try (Statement st = con.createStatement()) { + try (ResultSet rs = st.executeQuery(query)) { + while (rs.next()) { + Clob data1 = rs.getClob(2); + if (data1 != null) { + assertTrue(data1.length() == 0); + } + } + } + } + } +} \ No newline at end of file diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/GeometricTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/GeometricTest.java index e2c87104c98e3001c617a174d2b842c2363ad078..e14214c89bea640675fcf2e8153f581539e1f1fb 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/GeometricTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/GeometricTest.java @@ -45,7 +45,7 @@ public class GeometricTest extends BaseTest4 { @Parameterized.Parameters(name = "binary = {0}") public static Iterable data() { - Collection ids = new ArrayList(); + Collection ids = new ArrayList<>(); for (BinaryMode binaryMode : BinaryMode.values()) { ids.add(new Object[]{binaryMode}); } diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java index 009116a4d39227b78ff40511a28ff38796fcff02..4645386f4ccf0f2587bab0dc45a9ac4de1cf7786 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/Jdbc2TestSuite.java @@ -101,7 +101,6 @@ import org.junit.runners.Suite; DeepBatchedInsertStatementTest.class, JBuilderTest.class, MiscTest.class, - NotifyTest.class, DatabaseEncodingTest.class, ClientEncodingTest.class, diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PGPropertyTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PGPropertyTest.java index a5bb319fa586dc506c13c67e3c9181f03e6b68e5..0d21a45d37b35f3bd9ccbfd82e2eae2e76848d25 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PGPropertyTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PGPropertyTest.java @@ -28,8 +28,10 @@ import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.sql.DriverPropertyInfo; import java.util.ArrayList; +import java.util.HashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.TreeMap; @@ -126,6 +128,9 @@ public class PGPropertyTest { excluded.add("sslprivatekeyfactory"); excluded.add("ApplicationType"); excluded.add("TLSCiphersSupperted"); + excluded.add("enable_ce"); + excluded.add("priorityServers"); + excluded.add("forceTargetServerSlave"); // index PropertyDescriptors by name Map propertyDescriptors = diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PgCallableStatementTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PgCallableStatementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..46fec4c055cdf49979009240244069a794964d8b --- /dev/null +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PgCallableStatementTest.java @@ -0,0 +1,263 @@ +package org.postgresql.test.jdbc2; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.postgresql.test.TestUtil; +import org.postgresql.util.PGobject; + +import java.sql.*; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +public class PgCallableStatementTest extends BaseTest4 { + + @Before + public void setUp() throws Exception { + super.setUp(); + TestUtil.execute("set behavior_compat_options='proc_outparam_override'", con); + TestUtil.createCompositeType(con, "compfoos", "f1 int, f2 varchar(20), f3 varchar(20)"); + TestUtil.createTable(con, "test_user_type", "a int, b compfoos, c compfoos, d varchar(20)"); + String insertSQL = TestUtil.insertSQL("test_user_type", "1, (1,'demo','demo'), (1,'demo1','demo1'), " + + "'123456@email'"); + TestUtil.execute(insertSQL, con); + TestUtil.createTable(con, "test_tbl_commonType", "" + + "col_str varchar(26),\n" + + "col_bool bool,\n" + + "col_byte TINYINT,\n" + + "col_short smallint,\n" + + "col_int int,\n" + + "col_long bigint,\n" + + "col_float REAL,\n" + + "col_doule DOUBLE PRECISION,\n" + + "col_bigDecimal number,\n" + + "col_bytes bytea,\n" + + "col_date date,\n" + + "col_time time,\n" + + "col_timestamp timestamp,\n" + + "col_object varchar(52)"); + TestUtil.execute(TestUtil.insertSQL("test_tbl_commonType", "" + + "'abcdefghijklmnopqrstuvwxyz',\n" + + "true,\n" + + "12,\n" + + "123,\n" + + "888888888,\n" + + "999999999,\n" + + "123456.789123,\n" + + "123456.789123,\n" + + "99999999999999999999.1234567890123456,\n" + + "E'DEADBEEF',\n" + + "'2010-12-12',\n" + + "'21:21:21',\n" + + "'2003-04-12 04:05:06',\n" + + "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'"), con); + } + + @After + public void tearDown() throws SQLException { + TestUtil.dropType(con, "compfoos"); + TestUtil.dropTable(con, "test_user_type"); + } + + @Test + public void testOneCompositeTypeOutParam() throws SQLException { + Statement stmt = null; + CallableStatement cmt = null; + try { + stmt = con.createStatement(); + stmt.execute("CREATE OR REPLACE PROCEDURE test_proc_user_type_out(id in int,name out compfoos,address in " + + "int)\n" + + "AS\n" + + "BEGIN\n" + + "select b into name from test_user_type where a = id or a = address;\n" + + "END;\n"); + String query_str = "{call test_proc_user_type_out(?,?,?)}"; + cmt = con.prepareCall(query_str); + cmt.setInt(1, 1); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.setInt(3, 1); + cmt.execute(); + PGobject object = (PGobject) cmt.getObject(2); + assertEquals("(1,demo,demo)", object.getValue()); + assertEquals("[f1, f2, f3]", Arrays.toString(object.getStruct())); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + @Test + public void testMultipleCompositeTypeOutParam() throws SQLException { + Statement stmt = null; + CallableStatement cmt = null; + try { + stmt = con.createStatement(); + stmt.execute("CREATE OR REPLACE PROCEDURE test_proc_user_type_out(id in int,name out compfoos,address out" + + " compfoos,email out varchar(20))\n" + + "AS\n" + + "BEGIN\n" + + "select b into name from test_user_type where a = id;\n" + + "select c into address from test_user_type where a = id;\n" + + "select d into email from test_user_type where a = id;\n" + + "END;\n"); + String query_str = "{call test_proc_user_type_out(?,?,?,?)}"; + cmt = con.prepareCall(query_str); + cmt.setInt(1, 1); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.registerOutParameter(3, Types.STRUCT, "wumk3.compfoos"); + cmt.registerOutParameter(4, Types.VARCHAR); + cmt.execute(); + PGobject firstObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(firstObject.getStruct())); + assertEquals("(1,demo,demo)", firstObject.getValue()); + PGobject secondObject = (PGobject) cmt.getObject(3); + assertEquals("[f1, f2, f3]", Arrays.toString(secondObject.getStruct())); + assertEquals("(1,demo1,demo1)", secondObject.getValue()); + assertEquals("123456@email", cmt.getString(4)); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + @Test + public void testCommonTypesOutParam() throws SQLException { + Statement stmt = null; + CallableStatement cmt = null; + try { + stmt = con.createStatement(); + String createProcedure = "CREATE OR REPLACE PROCEDURE procedure_test(" + + "v_str OUT varchar(26)," + + "v_bool OUT bool," + + "v_byte OUT TINYINT," + + "v_short OUT smallint," + + "v_int OUT int," + + "v_long OUT bigint," + + "v_float OUT REAL," + + "v_doule OUT DOUBLE PRECISION," + + "v_bigDecimal OUT number," + + "v_bytes OUT bytea," + + "v_date OUT date," + + "v_time OUT time," + + "v_timestamp OUT timestamp," + + "v_object OUT varchar(52))" + + " AS " + + " BEGIN " + + "SELECT col_str INTO v_str FROM test_tbl_err_2;" + + "SELECT col_bool INTO v_bool FROM test_tbl_err_2;" + + "SELECT col_byte INTO v_byte FROM test_tbl_err_2;" + + "SELECT col_short INTO v_short FROM test_tbl_err_2;" + + "SELECT col_int INTO v_int FROM test_tbl_err_2;" + + "SELECT col_long INTO v_long FROM test_tbl_err_2;" + + "SELECT col_float INTO v_float FROM test_tbl_err_2;" + + "SELECT col_doule INTO v_doule FROM test_tbl_err_2;" + + "SELECT col_bigDecimal INTO v_bigDecimal FROM test_tbl_err_2;" + + "SELECT col_bytes INTO v_bytes FROM test_tbl_err_2;" + + "SELECT col_date INTO v_date FROM test_tbl_err_2;" + + "SELECT col_time INTO v_time FROM test_tbl_err_2;" + + "SELECT col_timestamp INTO v_timestamp FROM test_tbl_err_2;" + + "SELECT col_object INTO v_object FROM test_tbl_err_2;" + + " END;"; + stmt.execute(createProcedure); + String sql = "{call procedure_test(?,?,?,?,?,?,?,?,?,?,?,?,?,?)}"; + cmt = con.prepareCall(sql); + cmt.registerOutParameter(1, Types.VARCHAR); + cmt.registerOutParameter(2, Types.BOOLEAN); + cmt.registerOutParameter(3, Types.TINYINT); + cmt.registerOutParameter(4, Types.SMALLINT); + cmt.registerOutParameter(5, Types.INTEGER); + cmt.registerOutParameter(6, Types.BIGINT); + cmt.registerOutParameter(7, Types.REAL); + cmt.registerOutParameter(8, Types.DOUBLE); + cmt.registerOutParameter(9, Types.NUMERIC); + cmt.registerOutParameter(10, Types.BINARY); + cmt.registerOutParameter(11, Types.TIMESTAMP); + cmt.registerOutParameter(12, Types.TIME); + cmt.registerOutParameter(13, Types.TIMESTAMP); + cmt.registerOutParameter(14, Types.VARCHAR); + cmt.execute(); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /***************************************************************** + * 描述:测试复合类型参数的取值 + * 被测对象:PGobject + * 输入:复合类型值 + * 测试场景:构造不同复合类型参数的值,验证返回与输入一致 + * 期望输出:输入值与返回值一致 + ******************************************************************/ + @Test + public void testCompositeTypeValue() throws SQLException { + Statement stmt = null; + CallableStatement cmt = null; + try { + stmt = con.createStatement(); + stmt.execute("CREATE OR REPLACE PROCEDURE test_proc_user_type_out2(id in int,name out compfoos) " + + "AS " + + "BEGIN " + + "select b into name from test_user_type where a = id;" + + "END;"); + + // (1,'demo','demo') + TestUtil.execute(TestUtil.insertSQL("test_user_type", "3, (1,'demo','demo'), null, null"), con); + cmt = con.prepareCall("{call test_proc_user_type_out2(?,?)}"); + cmt.setInt(1, 3); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.execute(); + PGobject firstObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(firstObject.getStruct())); + assertEquals("(1,demo,demo)", firstObject.getValue()); + assertEquals("[1, demo, demo]", Arrays.toString(firstObject.getArrayValue())); + // (1,'','demo') + TestUtil.execute(TestUtil.insertSQL("test_user_type", "4, (1,'','demo'), null, null"), con); + cmt = con.prepareCall("{call test_proc_user_type_out2(?,?)}"); + cmt.setInt(1, 4); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.execute(); + PGobject secondObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(secondObject.getStruct())); + assertEquals("(1,,demo)", secondObject.getValue()); + assertEquals("[1, null, demo]", Arrays.toString(secondObject.getArrayValue())); + // (1,'"""demo","','(1,de",mo,demo) + TestUtil.execute(TestUtil.insertSQL("test_user_type", "5, (1,'\"\"\"demo\",\"','(1,de\",mo,demo)'), null," + + "null"), con); + cmt = con.prepareCall("{call test_proc_user_type_out2(?,?)}"); + cmt.setInt(1, 5); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.execute(); + PGobject thirdObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(thirdObject.getStruct())); + assertEquals("(1,\"\"\"\"\"\"\"demo\"\",\"\"\",\"(1,de\"\",mo,demo)\")", thirdObject.getValue()); + assertEquals("[1, \"\"\"\"\"\"\"demo\"\",\"\"\", \"(1,de\"\",mo,demo)\"]", Arrays.toString(thirdObject.getArrayValue())); + // (1,'"\,| ''tt','') + TestUtil.execute(TestUtil.insertSQL("test_user_type", "6, (1,'\"\\,| ''tt',''), null," + + "null"), con); + cmt = con.prepareCall("{call test_proc_user_type_out2(?,?)}"); + cmt.setInt(1, 6); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.execute(); + PGobject fourthObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(fourthObject.getStruct())); + assertEquals("(1,\"\"\"\\\\,| 'tt\",)", fourthObject.getValue()); + assertEquals("[1, \"\"\"\\\\,| 'tt\", null]", Arrays.toString(fourthObject.getArrayValue())); + // ('','','') + TestUtil.execute(TestUtil.insertSQL("test_user_type", "7, ('','',''), null," + + "null"), con); + cmt = con.prepareCall("{call test_proc_user_type_out2(?,?)}"); + cmt.setInt(1, 7); + cmt.registerOutParameter(2, Types.STRUCT, "wumk3.compfoos"); + cmt.execute(); + PGobject fifthObject = (PGobject) cmt.getObject(2); + assertEquals("[f1, f2, f3]", Arrays.toString(fifthObject.getStruct())); + assertEquals("(,,)", fifthObject.getValue()); + assertEquals("[null, null, null]", Arrays.toString(fifthObject.getArrayValue())); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } +} \ No newline at end of file diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ProcOutparamOverrideTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ProcOutparamOverrideTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b8fad27b4fff126a09230b8c6c48d138b7ca4c84 --- /dev/null +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ProcOutparamOverrideTest.java @@ -0,0 +1,265 @@ +package org.postgresql.test.jdbc2; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.postgresql.test.TestUtil; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Adaptation overload function use case set. + */ +public class ProcOutparamOverrideTest extends BaseTest4 { + + /** + * The sql of the create proc. + */ + private static final String PROC_SQL = "CREATE OR REPLACE PROCEDURE test_proc(param_1 out integer,param_2 out " + + "integer," + + "param_3 in integer) " + + "AS " + + "DECLARE " + + "BEGIN " + + "select (1 + param_3) into param_1; " + + "select (2 + param_3) into param_2; " + + "END;"; + + /** + * The sql of the create package. + */ + private static final String PACKAGE_SQL = "CREATE OR REPLACE package pck1 is " + + "procedure p1(a int,b out int); " + + "procedure p1(a2 int,b2 out varchar2); " + + "end pck1;"; + + /** + * The sql of the create package body. + */ + private static final String PACKAGE_BODY_SQL = "CREATE OR REPLACE package body pck1 is " + + "procedure p1(a int,b out int) is " + + "begin " + + "b = a + 2; " + + "end; " + + "procedure p1(a2 int,b2 out varchar2) is " + + "begin " + + "b2 = a2 || b2; " + + "end; " + + "end pck1;"; + + /** + * The sql of the create proc no out param. + */ + private static final String PROC_NO_OUTPARAM_SQL = "CREATE OR REPLACE PROCEDURE test_proc_1(id in integer,name in" + + " varchar) " + + "AS " + + "DECLARE " + + "BEGIN " + + "insert into test_1 values(id,name); " + + "END;"; + + /** + * The sql of the create table. + */ + private static final String CREATE_TABLE_SQL = "CREATE TABLE if not exists test_1(id int,name varchar(20))"; + + /** + * The sql of the set guc param behavior_compat_options + */ + private static final String TURN_ON_OVERRIDE = "set behavior_compat_options='proc_outparam_override'"; + + /** + * The sql of the set guc param behavior_compat_options + */ + private static final String TURN_OFF_OVERRIDE = "set behavior_compat_options=''"; + + @Before + public void setUp() throws Exception { + super.setUp(); + String[] databases = {"ora_compatible_db", "mysql_compatible_db", "td_compatible_db", "pg_compatible_db"}; + for (String database: databases) { + try { + TestUtil.execute(String.format("DROP DATABASE %s", database), con); + } catch (Exception exp) { + + } + } + TestUtil.execute("drop table if exists test_1", con); + TestUtil.execute("CREATE DATABASE ora_compatible_db DBCOMPATIBILITY 'A'", con); + TestUtil.execute("CREATE DATABASE mysql_compatible_db DBCOMPATIBILITY 'B';", con); + TestUtil.execute("CREATE DATABASE td_compatible_db DBCOMPATIBILITY 'C';", con); + TestUtil.execute("CREATE DATABASE pg_compatible_db DBCOMPATIBILITY 'PG';", con); + } + + @After + public void tearDown() throws SQLException { + String[] databases = {"ora_compatible_db", "mysql_compatible_db", "td_compatible_db", "pg_compatible_db"}; + for (String database: databases) { + try { + TestUtil.execute(String.format("DROP DATABASE %s", database), con); + } catch (Exception exp) { + + } + }; + } + + /***************************************************************** + * 描述:测试A兼容模式,重载开启与关闭下,存储过程的调用 + * 被测对象:PgCallableStatement + * 输入:存储过程名 + * 测试场景:开启重载,调用储存过程;关闭重载,调用存储过程 + * 期望输出:正确返回结果 + ******************************************************************/ + @Test + public void testOraCompatible() throws Exception { + Properties props = new Properties(); + props.setProperty("PGDBNAME", "ora_compatible_db"); + con = TestUtil.openDB(props); + verifyOutparamOverride(con); + verifyPackageReloadProc(con); + verifyPrepareStatement(con); + } + + /***************************************************************** + * 描述:测试PostgreSQL兼容模式,重载开启与关闭下,存储过程的调用 + * 被测对象:PgCallableStatement + * 输入:存储过程名 + * 测试场景:开启重载,调用储存过程;关闭重载,调用存储过程 + * 期望输出:正确返回结果 + ******************************************************************/ + @Test + public void testPgCompatible() throws Exception { + Properties props = new Properties(); + props.setProperty("PGDBNAME", "pg_compatible_db"); + con = TestUtil.openDB(props); + verifyOutparamOverride(con); + } + + /** + * Verify the result of reload open and close the stored procedure call. + * + * @param conn Database connection of different compatibility modes. + * @throws Exception if a JDBC or database problem occurs. + */ + private void verifyOutparamOverride(Connection conn) throws Exception { + Statement stmt = null; + CallableStatement cmt = null; + String callProc = "{call test_proc(?,?,?)}"; + try { + stmt = conn.createStatement(); + stmt.execute(TURN_ON_OVERRIDE); + stmt.execute(PROC_SQL); + cmt = conn.prepareCall(callProc); + cmt.registerOutParameter(1, Types.INTEGER); + cmt.registerOutParameter(2, Types.INTEGER); + cmt.setInt(3, 1); + cmt.execute(); + assertEquals(2, cmt.getInt(1)); + assertEquals(3, cmt.getInt(2)); + + stmt.execute(TURN_OFF_OVERRIDE); + cmt = conn.prepareCall(callProc); + cmt.registerOutParameter(1, Types.INTEGER); + cmt.registerOutParameter(2, Types.INTEGER); + cmt.setInt(3, 6); + cmt.execute(); + assertEquals(7, cmt.getInt(1)); + assertEquals(8, cmt.getInt(2)); + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /** + * package contains a stored procedure with the same name. + * + * @param conn Database connection of different compatibility modes. + * @throws Exception if a JDBC or database problem occurs. + */ + private void verifyPackageReloadProc(Connection conn) throws Exception { + Statement stmt = null; + CallableStatement cmt = null; + String callProc = "{call pck1.p1(?,?)}"; + try { + stmt = conn.createStatement(); + stmt.execute(TURN_ON_OVERRIDE); + stmt.execute(PACKAGE_SQL); + stmt.execute(PACKAGE_BODY_SQL); + cmt = conn.prepareCall(callProc); + cmt.setInt(1, 1); + cmt.registerOutParameter(2, Types.INTEGER); + cmt.execute(); + assertEquals(3, cmt.getInt(2)); + cmt = conn.prepareCall(callProc); + cmt.setInt(1, 2); + cmt.registerOutParameter(2, Types.VARCHAR); + cmt.execute(); + assertEquals("2", cmt.getString(2)); + + stmt.execute(TURN_OFF_OVERRIDE); +; + cmt = conn.prepareCall(callProc); + cmt.setInt(1, 4); + cmt.registerOutParameter(2, Types.VARCHAR); + cmt.execute(); + assertEquals("4", cmt.getString(2)); + + try { + cmt = conn.prepareCall(callProc); + cmt.setInt(1, 6); + cmt.registerOutParameter(2, Types.INTEGER); + cmt.execute(); + assertEquals(8, cmt.getInt(2)); + fail("can't run here!"); + } catch (Exception exp) { + } + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(cmt); + } + } + + /** + * PrepareStatement call proc. + * + * @param conn Database connection of different compatibility modes. + * @throws Exception if a JDBC or database problem occurs. + */ + private void verifyPrepareStatement(Connection conn) throws Exception { + Statement stmt = null; + PreparedStatement pstm = null; + try { + stmt = conn.createStatement(); + stmt.execute(CREATE_TABLE_SQL); + stmt.execute(PROC_NO_OUTPARAM_SQL); + stmt.execute(TURN_ON_OVERRIDE); + pstm = conn.prepareStatement("select * from test_proc_1(?,?)"); + pstm.setInt(1, 1); + pstm.setString(2, "Tom"); + pstm.execute(); + + stmt.execute(TURN_OFF_OVERRIDE); + pstm = conn.prepareStatement("select * from test_proc_1(?,?)"); + pstm.setInt(1, 2); + pstm.setString(2, "Jone"); + pstm.execute(); + + } finally { + TestUtil.closeQuietly(stmt); + TestUtil.closeQuietly(pstm); + } + } + +} \ No newline at end of file diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetMetaDataTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetMetaDataTest.java index a02625148114318f64128bd15c91e06ef70a92ef..858bae2fe42b1be4a45eac2c6d84a7bf18860762 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetMetaDataTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetMetaDataTest.java @@ -30,8 +30,11 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; @RunWith(Parameterized.class) public class ResultSetMetaDataTest extends BaseTest4 { @@ -145,12 +148,12 @@ public class ResultSetMetaDataTest extends BaseTest4 { assertEquals("text", rsmd.getColumnTypeName(2)); assertEquals(10, rsmd.getPrecision(3)); - assertEquals(2, rsmd.getScale(3)); - - assertEquals("public", rsmd.getSchemaName(1)); + + Set schemas = Arrays.stream(new String[]{"public", con.getSchema()}).collect(Collectors.toSet()); + assertTrue(schemas.contains(rsmd.getSchemaName(1))); assertEquals("", rsmd.getSchemaName(4)); - assertEquals("public", pgrsmd.getBaseSchemaName(1)); + assertTrue(schemas.contains(pgrsmd.getBaseSchemaName(1))); assertEquals("", pgrsmd.getBaseSchemaName(4)); assertEquals("rsmd1", rsmd.getTableName(1)); diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetTest.java index 918ac677d3f7c389ed28dd873974e2d0c8ae3e9e..20556bbed91ed1999fa222a09ac75df4d383310a 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetTest.java @@ -15,6 +15,7 @@ import static org.junit.Assume.assumeTrue; import org.postgresql.core.ServerVersion; import org.postgresql.jdbc.PreferQueryMode; import org.postgresql.test.TestUtil; +import org.postgresql.util.DataBaseCompatibility; import org.postgresql.util.PGobject; import org.junit.Test; diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/SearchPathLookupTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/SearchPathLookupTest.java index 5bc7f8ac68435cc41b183dd4e30638ef2f8dadcc..0ebd2ae20e188c32bdb2985cd2ee9317a337f860 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/SearchPathLookupTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/SearchPathLookupTest.java @@ -6,6 +6,7 @@ package org.postgresql.test.jdbc2; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.postgresql.core.BaseConnection; @@ -48,13 +49,14 @@ public class SearchPathLookupTest { TestUtil.createTable(con, "third_schema.x", "third_schema_field_n float"); TestUtil.createSchema(con, "last_schema"); TestUtil.createTable(con, "last_schema.x", "last_schema_field_n text"); - stmt.execute("SET search_path TO third_schema;"); - TypeInfo typeInfo = con.getTypeInfo(); - int OID = typeInfo.getPGType("x"); - ResultSet rs = stmt.executeQuery("SELECT 'third_schema.x'::regtype::oid"); - assertTrue(rs.next()); - assertEquals(OID, rs.getInt(1)); - assertTrue(!rs.next()); + stmt.execute("SET search_path TO third_schema"); + ResultSet rs1 = stmt.executeQuery("SELECT 'x'::regtype::oid"); + assertTrue(rs1.next()); + int OID = rs1.getInt(1); + ResultSet rs2 = stmt.executeQuery("SELECT 'third_schema.x'::regtype::oid"); + assertTrue(rs2.next()); + assertEquals(OID, rs2.getInt(1)); + assertFalse(rs2.next()); TestUtil.dropSchema(con, "first_schema"); TestUtil.dropSchema(con, "second_schema"); TestUtil.dropSchema(con, "third_schema"); @@ -84,13 +86,13 @@ public class SearchPathLookupTest { TestUtil.createTable(con, "third_schema.x", "third_schema_field_n float"); TestUtil.createSchema(con, "last_schema"); TestUtil.createTable(con, "last_schema.y", "last_schema_field_n text"); - stmt.execute("SET search_path TO first_schema, second_schema, last_schema, public;"); + stmt.execute("SET search_path TO first_schema, second_schema, last_schema, public"); TypeInfo typeInfo = con.getTypeInfo(); int OID = typeInfo.getPGType("y"); ResultSet rs = stmt.executeQuery("SELECT 'second_schema.y'::regtype::oid"); assertTrue(rs.next()); assertEquals(OID, rs.getInt(1)); - assertTrue(!rs.next()); + assertFalse(rs.next()); TestUtil.dropSchema(con, "first_schema"); TestUtil.dropSchema(con, "second_schema"); TestUtil.dropSchema(con, "third_schema"); @@ -114,10 +116,10 @@ public class SearchPathLookupTest { TypeInfo typeInfo = con.getTypeInfo(); int OID = typeInfo.getPGType("x"); ResultSet rs = stmt - .executeQuery("SELECT oid FROM pg_type WHERE typname = 'x' ORDER BY oid DESC LIMIT 1"); + .executeQuery("SELECT oid FROM pg_type WHERE typname = 'x' ORDER BY oid LIMIT 1"); assertTrue(rs.next()); assertEquals(OID, rs.getInt(1)); - assertTrue(!rs.next()); + assertFalse(rs.next()); TestUtil.dropSchema(con, "first_schema"); TestUtil.dropSchema(con, "second_schema"); } finally { diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java index 692f1df004dc53d935197185c18e59f2823a2563..9a921c300b40ee0d699ef4620d6a8389f22a1708 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/TimezoneTest.java @@ -15,6 +15,7 @@ import org.postgresql.test.TestUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.postgresql.util.DataBaseCompatibility; import java.sql.Connection; import java.sql.Date; @@ -69,6 +70,7 @@ public class TimezoneTest { private Calendar cGMT03; private Calendar cGMT05; private Calendar cGMT13; + private boolean isADatabase = true; public TimezoneTest() { TimeZone UTC = TimeZone.getTimeZone("UTC"); // +0000 always @@ -95,6 +97,7 @@ public class TimezoneTest { // This is not obvious, but the "gmt-3" timezone is actually 3 hours *ahead* of GMT // so will produce +03 timestamptz output con.createStatement().executeUpdate("set timezone = 'gmt-3'"); + isADatabase = DataBaseCompatibility.isADatabase(con); // System.err.println("++++++ TESTS START (" + getName() + ") ++++++"); } @@ -125,9 +128,15 @@ public class TimezoneTest { ResultSet rs = ps.executeQuery(); assertTrue(rs.next()); - checkDatabaseContents("SELECT tstz::text,ts::text,t::text,tz::text,d::text from testtimezone", - new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00", "15:00:00+03", - "2005-01-01"}); + if (isADatabase) { + checkDatabaseContents("SELECT tstz::text,ts::text,t::text,tz::text,d::text from testtimezone", + new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00", "15:00:00+03", + "2005-01-01 00:00:00"}); + } else { + checkDatabaseContents("SELECT tstz::text,ts::text,t::text,tz::text,d::text from testtimezone", + new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00", "15:00:00+03", + "2005-01-01"}); + } Timestamp ts; String str; @@ -205,7 +214,11 @@ public class TimezoneTest { ts = rs.getTimestamp(5, cGMT13); assertEquals(1104490800000L, ts.getTime()); // 2005-01-01 00:00:00 +1300 str = rs.getString(5); - assertEquals("date -> getString" + format, "2005-01-01", str); + if (!isADatabase) { + assertEquals("date -> getString" + format, "2005-01-01", str); + } else { + assertEquals("date -> getString" + format, "2005-01-01 00:00:00", str); + } assertTrue(!rs.next()); ps.close(); @@ -222,8 +235,13 @@ public class TimezoneTest { ResultSet rs = ps.executeQuery(); assertTrue(rs.next()); - checkDatabaseContents("SELECT tstz::text,ts::text,d::text from testtimezone", - new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "2005-01-01"}); + if (isADatabase) { + checkDatabaseContents("SELECT tstz::text,ts::text,d::text from testtimezone", + new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "2005-01-01 00:00:00"}); + } else { + checkDatabaseContents("SELECT tstz::text,ts::text,d::text from testtimezone", + new String[]{"2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "2005-01-01"}); + } Date d; @@ -423,22 +441,22 @@ public class TimezoneTest { for (int i = 0; i < PREPARE_THRESHOLD; i++) { con.createStatement().execute("delete from testtimezone"); PreparedStatement insertTimestamp = - con.prepareStatement("INSERT INTO testtimezone(seq,tstz,ts,tz,d) VALUES (?,?,?,?,?)"); + con.prepareStatement("INSERT INTO testtimezone(seq,tstz,ts,tz,d) VALUES (?,?,?,?,?)"); int seq = 1; - + Timestamp instant = new Timestamp(1104580800000L); // 2005-01-01 12:00:00 UTC Timestamp instantTime = new Timestamp(instant.getTime() % DAY); Timestamp instantDateJVM = new Timestamp( - instant.getTime() - (instant.getTime() % DAY) - TimeZone.getDefault().getRawOffset()); + instant.getTime() - (instant.getTime() % DAY) - TimeZone.getDefault().getRawOffset()); Timestamp instantDateUTC = new Timestamp( - instant.getTime() - (instant.getTime() % DAY) - cUTC.getTimeZone().getRawOffset()); + instant.getTime() - (instant.getTime() % DAY) - cUTC.getTimeZone().getRawOffset()); Timestamp instantDateGMT03 = new Timestamp( - instant.getTime() - (instant.getTime() % DAY) - cGMT03.getTimeZone().getRawOffset()); + instant.getTime() - (instant.getTime() % DAY) - cGMT03.getTimeZone().getRawOffset()); Timestamp instantDateGMT05 = new Timestamp( - instant.getTime() - (instant.getTime() % DAY) - cGMT05.getTimeZone().getRawOffset()); + instant.getTime() - (instant.getTime() % DAY) - cGMT05.getTimeZone().getRawOffset()); Timestamp instantDateGMT13 = new Timestamp(instant.getTime() - (instant.getTime() % DAY) - - cGMT13.getTimeZone().getRawOffset() + DAY); - + - cGMT13.getTimeZone().getRawOffset() + DAY); + // +0100 (JVM default) insertTimestamp.setInt(1, seq++); insertTimestamp.setTimestamp(2, instant); // 2005-01-01 13:00:00 +0100 @@ -446,7 +464,7 @@ public class TimezoneTest { insertTimestamp.setTimestamp(4, instant); // 13:00:00 +0100 insertTimestamp.setTimestamp(5, instant); // 2005-01-01 insertTimestamp.executeUpdate(); - + // UTC insertTimestamp.setInt(1, seq++); insertTimestamp.setTimestamp(2, instant, cUTC); // 2005-01-01 12:00:00 +0000 @@ -454,7 +472,7 @@ public class TimezoneTest { insertTimestamp.setTimestamp(4, instant, cUTC); // 12:00:00 +0000 insertTimestamp.setTimestamp(5, instant, cUTC); // 2005-01-01 insertTimestamp.executeUpdate(); - + // +0300 insertTimestamp.setInt(1, seq++); insertTimestamp.setTimestamp(2, instant, cGMT03); // 2005-01-01 15:00:00 +0300 @@ -462,7 +480,7 @@ public class TimezoneTest { insertTimestamp.setTimestamp(4, instant, cGMT03); // 15:00:00 +0300 insertTimestamp.setTimestamp(5, instant, cGMT03); // 2005-01-01 insertTimestamp.executeUpdate(); - + // -0500 insertTimestamp.setInt(1, seq++); insertTimestamp.setTimestamp(2, instant, cGMT05); // 2005-01-01 07:00:00 -0500 @@ -470,7 +488,7 @@ public class TimezoneTest { insertTimestamp.setTimestamp(4, instant, cGMT05); // 07:00:00 -0500 insertTimestamp.setTimestamp(5, instant, cGMT05); // 2005-01-01 insertTimestamp.executeUpdate(); - + // +1300 insertTimestamp.setInt(1, seq++); insertTimestamp.setTimestamp(2, instant, cGMT13); // 2005-01-02 01:00:00 +1300 @@ -478,23 +496,40 @@ public class TimezoneTest { insertTimestamp.setTimestamp(4, instant, cGMT13); // 01:00:00 +1300 insertTimestamp.setTimestamp(5, instant, cGMT13); // 2005-01-02 insertTimestamp.executeUpdate(); - + insertTimestamp.close(); - + // check that insert went correctly by parsing the raw contents in UTC - checkDatabaseContents( - "SELECT seq::text,tstz::text,ts::text,tz::text,d::text from testtimezone ORDER BY seq", - new String[][]{ - new String[]{"1", "2005-01-01 12:00:00+00", "2005-01-01 13:00:00", "13:00:00+01", - "2005-01-01"}, - new String[]{"2", "2005-01-01 12:00:00+00", "2005-01-01 12:00:00", "12:00:00+00", - "2005-01-01"}, - new String[]{"3", "2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00+03", - "2005-01-01"}, - new String[]{"4", "2005-01-01 12:00:00+00", "2005-01-01 07:00:00", "07:00:00-05", - "2005-01-01"}, - new String[]{"5", "2005-01-01 12:00:00+00", "2005-01-02 01:00:00", "01:00:00+13", - "2005-01-02"}}); + if (isADatabase) { + checkDatabaseContents( + "SELECT seq::text,tstz::text,ts::text,tz::text,d::text from testtimezone ORDER BY seq", + new String[][]{ + new String[]{"1", "2005-01-01 12:00:00+00", "2005-01-01 13:00:00", "13:00:00+01", + "2005-01-01 13:00:00"}, + new String[]{"2", "2005-01-01 12:00:00+00", "2005-01-01 12:00:00", "12:00:00+00", + "2005-01-01 12:00:00"}, + new String[]{"3", "2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00+03", + "2005-01-01 15:00:00"}, + new String[]{"4", "2005-01-01 12:00:00+00", "2005-01-01 07:00:00", "07:00:00-05", + "2005-01-01 07:00:00"}, + new String[]{"5", "2005-01-01 12:00:00+00", "2005-01-02 01:00:00", "01:00:00+13", + "2005-01-02 01:00:00"}}); + } else { + checkDatabaseContents( + "SELECT seq::text,tstz::text,ts::text,tz::text,d::text from testtimezone ORDER BY seq", + new String[][]{ + new String[]{"1", "2005-01-01 12:00:00+00", "2005-01-01 13:00:00", "13:00:00+01", + "2005-01-01"}, + new String[]{"2", "2005-01-01 12:00:00+00", "2005-01-01 12:00:00", "12:00:00+00", + "2005-01-01"}, + new String[]{"3", "2005-01-01 12:00:00+00", "2005-01-01 15:00:00", "15:00:00+03", + "2005-01-01"}, + new String[]{"4", "2005-01-01 12:00:00+00", "2005-01-01 07:00:00", "07:00:00-05", + "2005-01-01"}, + new String[]{"5", "2005-01-01 12:00:00+00", "2005-01-02 01:00:00", "01:00:00+13", + "2005-01-02"}}); + } + // // check results @@ -510,36 +545,59 @@ public class TimezoneTest { assertEquals(instant, rs.getTimestamp(2)); assertEquals(instant, rs.getTimestamp(3)); assertEquals(instantTime, rs.getTimestamp(4)); - assertEquals(instantDateJVM, rs.getTimestamp(5)); + if (isADatabase) { + assertEquals(instant, rs.getTimestamp(5)); + } else { + assertEquals(instantDateJVM, rs.getTimestamp(5)); + } assertTrue(rs.next()); assertEquals(seq++, rs.getInt(1)); assertEquals(instant, rs.getTimestamp(2, cUTC)); assertEquals(instant, rs.getTimestamp(3, cUTC)); assertEquals(instantTime, rs.getTimestamp(4, cUTC)); - assertEquals(instantDateUTC, rs.getTimestamp(5, cUTC)); + if (isADatabase) { + assertEquals(instant, rs.getTimestamp(5, cUTC)); + } else { + assertEquals(instantDateUTC, rs.getTimestamp(5, cUTC)); + } assertTrue(rs.next()); assertEquals(seq++, rs.getInt(1)); assertEquals(instant, rs.getTimestamp(2, cGMT03)); assertEquals(instant, rs.getTimestamp(3, cGMT03)); assertEquals(instantTime, rs.getTimestamp(4, cGMT03)); - assertEquals(instantDateGMT03, rs.getTimestamp(5, cGMT03)); - + if (isADatabase) { + assertEquals(instant, rs.getTimestamp(5, cGMT03)); + } else { + assertEquals(instantDateGMT03, rs.getTimestamp(5, cGMT03)); + } + + assertTrue(rs.next()); assertEquals(seq++, rs.getInt(1)); assertEquals(instant, rs.getTimestamp(2, cGMT05)); assertEquals(instant, rs.getTimestamp(3, cGMT05)); assertEquals(instantTime, rs.getTimestamp(4, cGMT05)); - assertEquals(instantDateGMT05, rs.getTimestamp(5, cGMT05)); - + if (isADatabase) { + assertEquals(instant, rs.getTimestamp(5, cGMT05)); + } else { + assertEquals(instantDateGMT05, rs.getTimestamp(5, cGMT05)); + } + + assertTrue(rs.next()); assertEquals(seq++, rs.getInt(1)); assertEquals(instant, rs.getTimestamp(2, cGMT13)); assertEquals(instant, rs.getTimestamp(3, cGMT13)); assertEquals(normalizeTimeOfDayPart(instantTime, cGMT13), rs.getTimestamp(4, cGMT13)); - assertEquals(instantDateGMT13, rs.getTimestamp(5, cGMT13)); - + if (isADatabase) { + assertEquals(instant, rs.getTimestamp(5, cGMT13)); + } else { + assertEquals(instantDateGMT13, rs.getTimestamp(5, cGMT13)); + } + + assertTrue(!rs.next()); ps.close(); } @@ -603,14 +661,26 @@ public class TimezoneTest { insertTimestamp.close(); // check that insert went correctly by parsing the raw contents in UTC - checkDatabaseContents( - "SELECT seq::text,tstz::text,ts::text,d::text from testtimezone ORDER BY seq", - new String[][]{ - new String[]{"1", "2004-12-31 23:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, - new String[]{"2", "2005-01-01 00:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, - new String[]{"3", "2004-12-31 21:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, - new String[]{"4", "2005-01-01 05:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, - new String[]{"5", "2004-12-31 11:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}}); + if (isADatabase) { + checkDatabaseContents( + "SELECT seq::text,tstz::text,ts::text,d::text from testtimezone ORDER BY seq", + new String[][]{ + new String[]{"1", "2004-12-31 23:00:00+00", "2005-01-01 00:00:00", "2005-01-01 00:00:00"}, + new String[]{"2", "2005-01-01 00:00:00+00", "2005-01-01 00:00:00", "2005-01-01 00:00:00"}, + new String[]{"3", "2004-12-31 21:00:00+00", "2005-01-01 00:00:00", "2005-01-01 00:00:00"}, + new String[]{"4", "2005-01-01 05:00:00+00", "2005-01-01 00:00:00", "2005-01-01 00:00:00"}, + new String[]{"5", "2004-12-31 11:00:00+00", "2005-01-01 00:00:00", "2005-01-01 00:00:00"}}); + } else { + + checkDatabaseContents( + "SELECT seq::text,tstz::text,ts::text,d::text from testtimezone ORDER BY seq", + new String[][]{ + new String[]{"1", "2004-12-31 23:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, + new String[]{"2", "2005-01-01 00:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, + new String[]{"3", "2004-12-31 21:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, + new String[]{"4", "2005-01-01 05:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}, + new String[]{"5", "2004-12-31 11:00:00+00", "2005-01-01 00:00:00", "2005-01-01"}}); + } // // check results // diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/TypesTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/TypesTest.java index d75c29bc005f898e0f8098aba2479d2cc99d4c25..25ac65d69b4d09380603255356e5f824a57ff4b1 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc3/TypesTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc3/TypesTest.java @@ -22,6 +22,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; +import java.util.Properties; public class TypesTest extends BaseTest4 { @@ -30,6 +31,8 @@ public class TypesTest extends BaseTest4 { @Override public void setUp() throws Exception { super.setUp(); + Properties props = new Properties(); + updateProperties(props); _conn = con; Statement stmt = _conn.createStatement(); stmt.execute( @@ -45,6 +48,12 @@ public class TypesTest extends BaseTest4 { super.tearDown(); } + @Override + protected void updateProperties(Properties props) { + super.updateProperties(props); + props.setProperty("use_boolean", "true"); + } + @Test public void testPreparedBoolean() throws SQLException { PreparedStatement pstmt = _conn.prepareStatement("SELECT ?,?,?,?"); diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java index 3c24a5e7d32d90b5f4c99eb494dcebfa58585ce3..d3920a06f28f175ca3b35bf1e7f3ef6da253678a 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc42/SetObject310Test.java @@ -23,6 +23,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Time; +import java.sql.Timestamp; import java.sql.Types; import java.time.LocalDate; import java.time.LocalDateTime; @@ -344,9 +345,16 @@ public class SetObject310Test { @Test public void testSetLocalDateWithoutType() throws SQLException { LocalDate data = LocalDate.parse("1971-12-15"); - java.sql.Date actual = insertThenReadWithoutType(data, "date_column", java.sql.Date.class); - java.sql.Date expected = java.sql.Date.valueOf("1971-12-15"); - assertEquals(expected, actual); + if (DataBaseCompatibility.isADatabase(con)) { + java.sql.Timestamp actual = insertThenReadWithoutType(data, "date_column", java.sql.Timestamp.class); + java.sql.Timestamp expected = new Timestamp(java.sql.Date.valueOf("1971-12-15").getTime()); + assertEquals(expected, actual); + + } else { + java.sql.Date actual = insertThenReadWithoutType(data, "date_column", java.sql.Date.class); + java.sql.Date expected = java.sql.Date.valueOf("1971-12-15"); + assertEquals(expected, actual); + } } /** diff --git a/pom.xml b/pom.xml index 659acf062400f37210c4d5dbceaabafc2745d1d1..5779e5db741cda9fc34fb8d30d1c8614e399496d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ 4.0.0 -com.huawei + com.huawei pgjdbc-aggregate pom @@ -11,16 +11,26 @@ https://github.com/pgjdbc/pgjdbc - jdbc + pgjdbc - + - https://github.com/pgjdbc/pgjdbc - scm:git:https://github.com/pgjdbc/pgjdbc.git - scm:git:git@github.com:pgjdbc/pgjdbc.git - REL42.2.5 + https://gitee.com/opengauss/openGauss-connector-jdbc + scm:git:https://gitee.com/opengauss/openGauss-connector-jdbc.git + scm:git:git@gitee.com:opengauss/openGauss-connector-jdbc.git + REL42.2.5 + + + sonatype-nexus-snapshots + https://s01.oss.sonatype.org/content/repositories/snapshots + + + sonatype-nexus-staging + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + diff --git a/prepare_demo.sh b/prepare_demo.sh deleted file mode 100644 index 5213d467418e768ed2d9dcdabd1db150e002aef6..0000000000000000000000000000000000000000 --- a/prepare_demo.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd shade -mvn clean install -Dmaven.test.skip=true -rm -rf temp -mkdir temp -cp target/demo-0.0.1-SNAPSHOT.jar ./temp/ -cd temp -jar -xf demo-0.0.1-SNAPSHOT.jar -find ./com -name "*" | sort | xargs zip demo-0.0.1-SNAPSHOT_new.jar -mvn install:install-file -Dfile=./demo-0.0.1-SNAPSHOT_new.jar -DgroupId=com.huawei -DartifactId=demo-0.0.1-SNAPSHOT -Dversion=0.0.1 -Dpackaging=jar diff --git a/prepare_maven.sh b/prepare_maven.sh deleted file mode 100644 index dc3ad61202c17fcd62c4bcbfa243367c94b0be6e..0000000000000000000000000000000000000000 --- a/prepare_maven.sh +++ /dev/null @@ -1,22 +0,0 @@ -echo begin run -mkdir libs -for src in `find open_source -name '*.jar'` -do - cp $src ./libs/ -done -JDBC_DIR=$(dirname $(readlink -f $0)) -cd ${JDBC_DIR} -rm -rf "${JDBC_DIR}/jdbc" -cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r - -mvn install:install-file -Dfile=./libs/commons-logging-1.2.jar -DgroupId=commons-logging -DartifactId=commons-logging -Dversion=1.2 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/commons-codec-1.11.jar -DgroupId=commons-codec -DartifactId=commons-codec -Dversion=1.11 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/httpclient-4.5.13.jar -DgroupId=org.apache.httpcomponents -DartifactId=httpclient -Dversion=4.5.13 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/httpcore-4.4.13.jar -DgroupId=org.apache.httpcomponents -DartifactId=httpcore -Dversion=4.4.13 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/fastjson-1.2.70.jar -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.2.70 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/joda-time-2.10.6.jar -DgroupId=joda-time -DartifactId=joda-time -Dversion=2.10.6 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/jackson-databind-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-databind -Dversion=2.11.2 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/jackson-core-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-core -Dversion=2.11.2 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/jackson-annotations-2.11.2.jar -DgroupId=com.fasterxml.jackson.core -DartifactId=jackson-annotations -Dversion=2.11.2 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/slf4j-api-1.7.30.jar -DgroupId=org.slf4j -DartifactId=slf4j-api -Dversion=1.7.30 -Dpackaging=jar -mvn install:install-file -Dfile=./libs/java-sdk-core-3.0.12.jar -DgroupId=com.huawei.apigateway -DartifactId=hw-java-sdk-core -Dversion=3.0.12 -Dpackaging=jar diff --git a/prepare_windows_build.sh b/prepare_windows_build.sh deleted file mode 100644 index 650f654018e3b5a54d437be1d05720489dc37aee..0000000000000000000000000000000000000000 --- a/prepare_windows_build.sh +++ /dev/null @@ -1,90 +0,0 @@ -#/bin/bash -echo begin run -BUILD_FAILED=1 -die() -{ - echo "ERROR: $@" - exit $BUILD_FAILED -} - -JDBC_DIR=$(dirname $(readlink -f $0)) -LOG_FILE=$JDBC_DIR/logfile -export JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8" -export COMMIT=$(git rev-parse --short HEAD) -export OPENGAUSS_PACKAGE_NAME="org.opengauss"; - -export GS_VERSION="compiled at $(date +%Y-%m-%d-%H:%M:%S) build ${COMMIT}" -export OUTPUT_DIR="${JDBC_DIR}/output" -export CLASSPATH=".:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar" - -make_output_dir() -{ - if [ ! -d "${OUTPUT_DIR}" ]; then - mkdir ${OUTPUT_DIR} - fi - cd ${OUTPUT_DIR} - rm -rf *.jar -} - -build_postgres() -{ - cd ${JDBC_DIR}/ - rm -rf "${JDBC_DIR}/jdbc" - cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r - cd "${JDBC_DIR}/jdbc" - find . -name 'Driver.java' | xargs sed -i "s/@GSVERSION@/${GS_VERSION}/g" - mvn clean install -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 - if [ $? -ne 0 ]; then - die "mvn failed." - fi - version=`awk '/[^<]+<\/version>/{gsub(/|<\/version>/,"",$1);print $1;exit;}' ${JDBC_DIR}/jdbc/pom.xml` - mv ${JDBC_DIR}/jdbc/target/opengauss-jdbc-${version}.jar ${OUTPUT_DIR}/postgresql.jar - echo "Successfully make postgresql.jar package in ${OUTPUT_DIR}/postgresql.jar" -} - -build_opengauss() -{ - cd ${JDBC_DIR} - rm -rf "${JDBC_DIR}/jdbc" - cp "${JDBC_DIR}/pgjdbc" "${JDBC_DIR}/jdbc" -r - cd "${JDBC_DIR}/jdbc" - find . -name 'Driver.java' | xargs sed -i "s/@GSVERSION@/${GS_VERSION}/g" - find . -name 'Driver.java' | xargs sed -i "s/jdbc:postgresql:/jdbc:opengauss:/g" - find . -name 'java.sql.Driver' | xargs sed -i "s#org\.postgresql#${OPENGAUSS_PACKAGE_NAME}#g" - find . -name '*.java' -type f | xargs sed -i "s#org\.postgresql#${OPENGAUSS_PACKAGE_NAME}#g" - if [ $? -ne 0 ]; then - die "failed to replace url name" - fi - find . -name 'BaseDataSource.java' | xargs sed -i "s/jdbc:postgresql:/jdbc:opengauss:/g" - if [ $? -ne 0 ]; then - die "fail to replace url name in BaseDataSource" - fi - - version=`awk '/[^<]+<\/version>/{gsub(/|<\/version>/,"",$1);print $1;exit;}' ${JDBC_DIR}/jdbc/pom.xml` - mvn clean install -Dmaven.test.skip=true >> "$LOG_FILE" 2>&1 - cp ${JDBC_DIR}/jdbc/target/opengauss-jdbc-${version}.jar ${OUTPUT_DIR}/ - echo "Successfully make opengauss-jdbc jar package in ${OUTPUT_DIR}/opengauss-jdbc-${version}.jar" -} - -tar_output() -{ - cd ${OUTPUT_DIR}/ - tar -zcvf ${JDBC_DIR}/openGauss-${version}-JDBC.tar.gz *.jar 2>&1 1>null - echo "Successfully make jdbc jar package in ${JDBC_DIR}/openGauss-${version}-JDBC.tar.gz" -} - -function clean() -{ - if [ -d "${JDBC_DIR}/jdbc" ]; then - rm -rf "${JDBC_DIR}/jdbc" - fi - if [ -f "${LOG_FILE}" ]; then - rm -rf "${LOG_FILE}" - fi -} - -make_output_dir -build_postgres -build_opengauss -tar_output -clean diff --git a/shade/pom.xml b/shade/pom.xml deleted file mode 100644 index ff7dc1b7dd931e020a620877574a8f90707062ce..0000000000000000000000000000000000000000 --- a/shade/pom.xml +++ /dev/null @@ -1,166 +0,0 @@ - - - 4.0.0 - com.huawei - demo - 0.0.1-SNAPSHOT - - - commons-logging - commons-logging - 1.2 - - - commons-codec - commons-codec - 1.11 - - - org.apache.httpcomponents - httpclient - 4.5.13 - - - org.apache.httpcomponents - httpcore - 4.4.13 - - - com.alibaba - fastjson - 1.2.75 - - - joda-time - joda-time - 2.10.6 - - - com.fasterxml.jackson.core - jackson-databind - 2.11.2 - - - com.fasterxml.jackson.core - jackson-core - 2.11.2 - - - com.fasterxml.jackson.core - jackson-annotations - 2.11.2 - - - com.huawei.apigateway - hw-java-sdk-core - 3.0.12 - - - org.slf4j - slf4j-api - 1.7.30 - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.0 - - false - - - - package - - shade - - - - - org.slf4j - com.huawei.shade.org.slf4j - - - org.apache - com.huawei.shade.org.apache - - - com.alibaba.fastjson - com.huawei.shade.com.alibaba.fastjson - - - org.joda - com.huawei.shade.org.joda - - - com.fasterxml - com.huawei.shade.com.fasterxml - - - com.cloud - com.huawei.shade.com.cloud - - - - - org.slf4j:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - org.apache.httpcomponents:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - com.alibaba:fastjson:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - joda-time:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - jackson-databind:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - jackson-core:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - jackson-annotations:* - - META-INF/LICENSE.txt - META-INF/NOTICE.txt - - - - - - - - - - -