Merge remote-tracking branch 'upstream/master'

This commit is contained in:
wuyuechuan 2020-08-06 19:05:38 +08:00
commit 5a69361717
286 changed files with 15617 additions and 5415 deletions

View File

@ -42,17 +42,23 @@ install_oracle_fdw:
endif
ifeq ($(enable_multiple_nodes), yes)
install: install_mysql_fdw install_oracle_fdw
install:
$(MAKE) install_mysql_fdw
$(MAKE) install_oracle_fdw
$(MAKE) -C contrib/hstore $@
$(MAKE) -C src/distribute/kernel/extension/packages $@
$(MAKE) -C contrib/pagehack $@
$(MAKE) -C contrib/pg_stat_statements $@
$(MAKE) -C contrib/pg_xlogdump $@
$(MAKE) -C contrib/gsredistribute $@
$(MAKE) -C src/distribute/kernel/extension/dimsearch $@
$(MAKE) -C src/distribute/kernel/extension/tsdb $@
+@echo "PostgreSQL installation complete."
else
install: install_mysql_fdw install_oracle_fdw
install:
$(MAKE) install_mysql_fdw
$(MAKE) install_oracle_fdw
$(MAKE) -C contrib/pg_stat_statements $@
+@echo "openGauss installation complete."
endif

603
README.en.md Normal file
View File

@ -0,0 +1,603 @@
![openGauss Logo](doc/openGauss-logo.png "openGauss logo")
English | [简体中文](./README.md)
- [What Is openGauss](#what-is-opengauss)
- [Installation](#installation)
- [Creating a Configuration File](#creating-a-configuration-file)
- [Initializing the Installation Environment](#initializing-the-installation-environment)
- [Executing Installation](#executing-installation)
- [Uninstalling the openGauss](#uninstalling-the-openGauss)
- [Compilation](#compilation)
- [Overview](#overview)
- [OS and Software Dependency Requirements](#os-and-software-dependency-requirements)
- [Downloading openGauss](#downloading-openGauss)
- [Compiling Third-Party Software](#compiling-third-party-software)
- [Compiling by build.sh](#compiling-by-build.sh)
- [Compiling by Command](#compiling-by-command)
- [Compiling the Installation Package](#compiling-the-installation-package)
- [Quick Start](#quick-start)
- [Docs](#docs)
- [Community](#community)
- [Governance](#governance)
- [Communication](#communication)
- [Contribution](#contribution)
- [Release Notes](#release-notes)
- [License](#license)
## What Is openGauss
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.
<img src="doc/openGauss-architecture.en.png" alt="openGauss Architecture" width="600"/>
**High Performance**
openGauss breaks through the bottleneck of multi-core CPU, 2-way Kunpeng 128 core 1.5 million TPMC on disk-based row store and 3.5 million TPMC on MOT (Memory-Optimized Tables) Engine.
**Partitions**
Divide key data structure shared by internal threads into different partitions to reduce lock access conflicts. For example, CLOG uses partition optimization to solve the bottleneck of ClogControlLock.
**NUMA Structure**
Malloc key data structures help reduce cross CPU access. The global PGPROC array is divided into several parts according to the number of NUMA nodes, solving the bottleneck of ProcArrayLock.
**Binding Cores**
Bind NIC interrupts to different cores and bind cores to different background threads to avoid performance instability due to thread migration between cores.
**ARM Optimization**
Optimize atomic operations based on ARM platform LSE instructions, implementing efficient operation of critical sections.
**SQL Bypass**
Optimize SQL execution process through SQL bypass, reducing CPU execution overhead.
**High Reliability**
Under normal service loads, the RTO is less than 10 seconds, reducing the service interruption time caused by node failure.
**Parallel Recovery**
When the Xlog is transferred to the standby node, the standby node flushs the Xlog to storage medium. At the meantime, the Xlog is sent to the redo recovery dispatch thread. The dispatch thread sends the Xlog to multiple parallel recovery threads to replay. Ensure that the redo speed of the standby node keeps up with the generation speed of the primary host. The standby node is ready in real time, which can be promoted to primary instantly.
**MOT Engine (beta release)**
The Memory-Optimized Tables (MOT) storage engine is a transactional rowstore optimized for many-core and large memory and delivering extreme OLTP performance and high resources utilization. With data and indexes stored totally in-memory, a NUMA-aware design, algorithms that eliminate lock and latch contention and query native compilation (JIT), MOT provides low latency data access and more efficient transaction execution. See [MOT Engine documentation](https://opengauss.org/en/docs/1.0.0/docs/Developerguide/mot.html).
**Security**
openGauss supports account management, account authentication, account locking, password complexity check, privilege management and verification, transmission encryption, and operation audit, protecting service data security.
**Easy Operation and Maintenance**
openGauss integrates AI algorithms into databases, reducing the burden of database maintenance.
- **SQL Prediction**
openGauss supports SQL execution time prediction based on collected historical performance data.
- **SQL Diagnoser**
openGauss supports the diagnoser for SQL execution statements, finding out slow queries in advance..
- **Automatical Parameter Adjustment**
openGauss supports automatically adjusting database parameters, reducing the cost and time of parameter adjustment.
## Installation
### Creating a Configuration File
Before installing the openGauss, you need to create the clusterconfig.xml file. The configuration file in the XML format contains the information about the server where the openGauss is deployed, installation path, IP address, and port number. This file is used to guide how to deploy the openGauss. You need to configure the configuration file according to the actual deployment requirements.
The following describes how to create an XML configuration file based on the deployment solution of one primary node and one standby node.
The information of value is only an example. You can replace it as required. Each line of information is commented out.
```
<?xml version="1.0" encoding="utf-8"?>
<ROOT>
<!-- Overall information -->
<CLUSTER>
<!-- Database name -->
<PARAM name="clusterName" value="dbCluster" />
<!-- Database node name (hostname) -->
<PARAM name="nodeNames" value="node1_hostname,node2_hostname"/>
<!-- Node IP addresses corresponding to the node names, respectively -->
<PARAM name="backIp1s" value="192.168.0.1,192.168.0.2"/>
<!-- Database installation path -->
<PARAM name="gaussdbAppPath" value="/opt/huawei/install/app" />
<!-- Log directory -->
<PARAM name="gaussdbLogPath" value="/var/log/omm" />
<!-- Temporary file directory -->
<PARAM name="tmpMppdbPath" value="/opt/huawei/tmp"/>
<!-- Database tool directory -->
<PARAM name="gaussdbToolPath" value="/opt/huawei/install/om" />
<!--Directory of the core file of the database -->
<PARAM name="corePath" value="/opt/huawei/corefile"/>
<!-- openGauss deployment type. A single-instance cluster is used as an example here, that is, one primary node and multiple standby nodes are deployed. -->
<PARAM name="clusterType" value="single-inst"/>
</CLUSTER>
<!-- Information about node deployment on each server -->
<DEVICELIST>
<!-- Information about the node deployment on node1 -->
<DEVICE sn="node1_hostname">
<!-- Host name of node1 -->
<PARAM name="name" value="node1_hostname"/>
<!-- AZ where node1 is located and AZ priority -->
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- IP address of node1. If only one NIC is available for the server, set backIP1 and sshIP1 to the same IP address. -->
<PARAM name="backIp1" value="192.168.0.1"/>
<PARAM name="sshIp1" value="192.168.0.1"/>
<!--DBnode-->
<PARAM name="dataNum" value="1"/>
<!-- Database node port number -->
<PARAM name="dataPortBase" value="15400"/>
<!-- Data directory on the primary database node and data directories of standby nodes -->
<PARAM name="dataNode1" value="/opt/huawei/install/data/dn,node2_hostname,/opt/huawei/install/data/dn"/>
<!-- Number of nodes for which the synchronization mode is set on the database node -->
<PARAM name="dataNode1_syncNum" value="0"/>
</DEVICE>
<!-- Information about the node deployment on node2 -->
<DEVICE sn="node2_hostname">
<!-- Host name of node2 -->
<PARAM name="name" value="node2_hostname"/>
<!-- AZ where node2 is located and AZ priority -->
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- IP address of node2. If only one NIC is available for the server, set backIP1 and sshIP1 to the same IP address. -->
<PARAM name="backIp1" value="192.168.0.2"/>
<PARAM name="sshIp1" value="192.168.0.2"/>
</DEVICE>
</DEVICELIST>
</ROOT>
```
### Initializing the Installation Environment
After the openGauss configuration file is created, you need to run the gs_preinstall script to prepare the account and environment so that you can perform openGauss installation and management operations with the minimum permission, ensuring system security.
Executing the **gs_preinstall** script enables the system to automatically complete the following installation preparations:
- Sets kernel parameters for the SUSE Linux OS to improve server load performance. The kernel parameters directly affect database running status. Reconfigure them only when necessary.
- Automatically copies the clusteropenGauss configuration files and installation packages to the same directory on each clusteropenGauss host.
- If the installation user and user group of the clusteropenGauss do not exist, the system automatically creates them.
- Reads the directory information in the clusteropenGauss configuration file, creates the directory, and grants the directory permission to the installation user.
**Precautions**
- You must check the upper-layer directory permissions to ensure that the user has the read, write, and execution permissions on the installation package and configuration file directory.
- The mapping between each host name and IP address in the XML configuration file must be correct.
- Only user root is authorized to run the gs_preinstall command.
**Procedure**
1. Log in to any host where the openGauss is to be installed as user root and create a directory for storing the installation package as planned.
```
mkdir -p /opt/software/openGauss
chmod 755 -R /opt/software
```
> **NOTE:**
>
> - Do not create the directory in the home directory or subdirectory of any openGauss user because you may lack permissions for such directories.
> - The openGauss user must have the read and write permissions on the /opt/software/openGauss directory.
2. Upload the installation package openGauss-x.x.x-openEULER-64bit.tar.gz and the configuration file clusterconfig.xml to the directory created in the previous step.
3. Go to the directory for storing the uploaded software package and decompress the package openGauss-x.x.x-openEULER-64bit.tar.gz.After the installation package is decompressed, the script subdirectory is automatically generated in /opt/software/openGauss. OM tool scripts such as gs_preinstall are generated in the script subdirectory.
```
cd /opt/software/openGauss
tar -zxvf openGauss-x.x.x-openEULER-64bit.tar.gz
```
4. Go to the directory for storing tool scripts.
```
cd /opt/software/openGauss/script
```
5. If the openEuler operating system is used, run the following command to open the **performance.sh** file, comment out **sysctl -w vm.min_free_kbytes=112640 &> /dev/null** using the number sign (#), press **Esc** to enter the command mode, and run the **:wq** command to save the modification and exit.
```
vi /etc/profile.d/performance.sh
```
6. To ensure that the OpenSSL version is correct, load the lib library in the installation package before preinstallation. Run the following command. {packagePath} indicates the path where the installation package is stored. In this example, the path is /opt/software/openGauss.
```
export LD_LIBRARY_PATH={packagePath}/script/gspylib/clib:$LD_LIBRARY_PATH
```
7. To ensure successful installation, check whether the values of hostname and /etc/hostname are the same. During preinstallation, the host name is checked.
8. Execute gs_preinstall to configure the installation environment. If the shared environment is used, add the --sep-env-file=ENVFILE parameter to separate environment variables to avoid mutual impact with other users. The environment variable separation file path is specified by users.
Execute gs_preinstall in interactive mode. During the execution, the mutual trust between users root and between clusteropenGauss users is automatically established.
```
./gs_preinstall -U omm -G dbgrp -X /opt/software/openGauss/clusterconfig.xml
```
omm is the database administrator (also the OS user running the openGauss), dbgrp is the group name of the OS user running the openGauss, and /opt/software/ openGauss/clusterconfig.xml is the path of the openGauss configuration file. During the execution, you need to determine whether to establish mutual trust as prompted and enter the password of user root or the openGauss user.
### Executing Installation
After the openGauss installation environment is prepared by executing the pre-installation script, deploy openGauss based on the installation process.
**Prerequisites**
- You have successfully executed the gs_preinstall script.
- All the server OSs and networks are functioning properly.
- You have checked that the locale parameter for each server is set to the same value.
**Procedure**
1. (Optional) Check whether the installation package and openGauss configuration file exist in the planned directories. If no such package or file exists, perform the preinstallation again..
2. Log in to any host of the openGauss and switch to the omm user.
```
su - omm
```
> **NOTE:**
>
> - omm indicates the user specified by the -U parameter in the gs_preinstall script.
> - You need to execute the gs_install script as user omm specified in the gs_preinstall script. Otherwise, an execution error will be reported.
3. Use gs_install to install the openGauss. If the openGauss is installed in environment variable separation mode, run the source command to obtain the environment variable separation file ENVFILE.
```
gs_install -X /opt/software/openGauss/clusterconfig.xml
```
/opt/software/openGauss/script/clusterconfig.xml is the path of the openGauss configuration file. During the execution, you need to enter the database password as prompted. The password must meet complexity requirements. To ensure that you can use the database properly, remember the entered database password.
The password must meet the following complexity requirements:
- Contain at least eight characters.
- Cannot be the same as the username, the current password (ALTER), or the current password in an inverted sequence.
- Contain at least three of the following: uppercase characters (A to Z), lowercase characters (a to z), digits (0 to 9), and other characters (limited to ~!@#$%^&*()-_=+\|[{}];:,<.>/?).
4. After the installation is successful, manually delete the trust between users root on the host, that is, delete the mutual trust file on each openGauss database node.
```
rm -rf ~/.ssh
```
### Uninstalling the openGauss
The process of uninstalling the openGauss includes uninstalling the openGauss and clearing the environment of the openGauss server.
#### **Executing Uninstallation**
The openGauss provides an uninstallation script to help users uninstall the openGauss.
**Procedure**
1. Log in as the OS user omm to the host where the CN is located.
2. Execute the gs_uninstall script to uninstall the database cluster.
```
gs_uninstall --delete-data
```
Alternatively, execute uninstallation on each openGauss node.
```
gs_uninstall --delete-data -L
```
#### **Deleting openGauss Configurations**
After the openGauss is uninstalled, execute the gs_postuninstall script to delete configurations from all servers in the openGauss if you do not need to re-deploy the openGauss using these configurations. These configurations are made by the gs_preinstall script.
**Prerequisites**
- The openGauss uninstallation task has been successfully executed.
- User root is trustworthy and available.
- Only user root is authorized to run the gs_postuninstall command.
**Procedure**
1. Log in to the openGauss server as user root.
2. Run the ssh Host name command to check whether mutual trust has been successfully established. Then, enter exit.
```
plat1:~ # ssh plat2
Last login: Tue Jan 5 10:28:18 2016 from plat1
plat2:~ # exit
logout
Connection to plat2 closed.
plat1:~ #
```
3. Go to the following path:
```
cd /opt/software/openGauss/script
```
4. Run the gs_postuninstall command to clear the environment. If the openGauss is installed in environment variable separation mode, run the source command to obtain the environment variable separation file ENVFILE.
```
./gs_postuninstall -U omm -X /opt/software/openGauss/clusterconfig.xml --delete-user --delete-group
```
Alternatively, locally use the gs_postuninstall tool to clear each openGauss node.
```
./gs_postuninstall -U omm -X /opt/software/openGauss/clusterconfig.xml --delete-user --delete-group -L
```
omm is the name of the OS user who runs the openGauss, and the path of the openGauss configuration file is /opt/software/openGauss/clusterconfig.xml.
If the cluster is installed in environment variable separation mode, delete the environment variable separation parameter ENV obtained by running the source command.
```
unset MPPDB_ENV_SEPARATE_PATH
```
5. Delete the mutual trust between the users root on each openGauss database node.
## Compilation
### Overview
To compile openGauss, you need two components: openGauss-server and binarylibs.
- openGauss-server: main code of openGauss. You can obtain it from the open source community.
- binarylibs: third party open source software that openGauss depends on. You can obtain it by compiling the openGauss-third_party code or downloading from the open source community on which we have compiled a copy and uploaded it . The first method will be introduced in the following chapter.
Before you compile openGauss, please check the OS and software dependency requirements.
You can compile openGauss by build.sh, a one-click shell tool, which we will introduce later, or compile by command. Also, an installation package is produced by build.sh.
### OS and Software Dependency Requirements
The following OSs are supported:
- CentOS 7.6 (x86 architecture)
- openEuler-20.03-LTS (aarch64 architecture)
The following table lists the software requirements for compiling the openGauss.
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 | Recommended Version |
| ------------- | ------------------- |
| libaio-devel | 0.3.109-13 |
| flex | 2.5.31 or later |
| bison | 2.7-4 |
| ncurses-devel | 5.9-13.20130511 |
| glibc.devel | 2.17-111 |
| patch | 2.7.1-10 |
| lsb_release | 4.1 |
### Downloading openGauss
You can download openGauss-server and openGauss-third_party from open source community.
https://opengauss.org/zh/
From the following website, you can obtain the binarylibs we have compiled. Please unzip it and rename to **binarylibs** after you download.
https://opengauss.obs.cn-south-1.myhuaweicloud.com/1.0.0/openGauss-third_party_binarylibs.tar.gz
Now we have completed openGauss code. For example, we store it in following directories.
- /sda/openGauss-server
- /sda/binarylibs
- /sda/openGauss-third_party
### Compiling Third-Party Software
Before compiling the openGauss, compile and build the open-source and third-party software on which the openGauss depends. These open-source and third-party software is stored in the openGauss-third_party code repository and usually needs to be built only once. If the open-source software is updated, rebuild the software.
You can also directly obtain the output file of the open-source software compilation and build from the **binarylibs** repository.
If you want to compile third-party by yourself, please go to openGauss-third_party repository to see details.
After the preceding script is executed, the final compilation and build result is stored in the **binarylibs** directory at the same level as **openGauss-third_party**. These files will be used during the compilation of **openGauss-server**.
### Compiling code
##### Compiling by build.sh
build.sh in openGauss-server is an important script tool during compilation. It integrates software installation and compilation and product installation package compilation functions to quickly compile and package code.
The following table describes the parameters.
| Option | Default Value | Parameter | Description |
| :----- | :--------------------------- | :------------------------------------- | :----------------------------------------------------------- |
| -h | Do not use this option. | - | Help menu. |
| -m | release | [debug &#124; release &#124; memcheck] | Selects the target version. |
| -3rd | ${Code directory}/binarylibs | [binarylibs path] | Specifies the path of binarylibs. The path must be an absolute path. |
| -pkg | Do not use this option. | - | Compresses the code compilation result into an installation package. |
| -nopt | Do not use this option. | - | On kunpeng platform, like 1616 version, without LSE optimized. |
> **NOTICE:**
>
> - **-m [debug | release | memcheck]** indicates that three target versions can be selected:
> - **release**: indicates that the binary program of the release version is generated. During compilation of this version, the GCC high-level optimization option is configured to remove the kernel debugging code. This option is usually used in the generation environment or performance test environment.
> - **debug**: indicates that a binary program of the debug version is generated. During compilation of this version, the kernel code debugging function is added, which is usually used in the development self-test environment.
> - **memcheck**: indicates that a binary program of the memcheck version is generated. During compilation of this version, the ASAN function is added based on the debug version to locate memory problems.
> - **-3rd [binarylibs path]** is the path of **binarylibs**. By default, **binarylibs** exists in the current code folder. If **binarylibs** is moved to **openGauss-server** or a soft link to **binarylibs** is created in **openGauss-server**, you do not need to specify the parameter. However, if you do so, please note that the file is easy to be deleted by the **git clean** command.
> - Each option in this script has a default value. The number of options is small and the dependency is simple. Therefore, this script is easy to use. If the required value is different from the default value, set this parameter based on the actual requirements.
Now you know the usage of build.sh, so you can compile the openGauss-server by one command with build.sh.
```
[user@linux openGauss-server]$ sh build.sh -m [debug | release | memcheck] -3rd [binarylibs path]
```
For example:
```
[user@linux openGauss-server]$ sh build.sh # Compile openGauss of the release version. The binarylibs or its soft link must exist in the code directory. Otherwise, the operation fails.
[user@linux openGauss-server]$ sh build.sh -m debug -3rd /sda/binarylibs # Compilate openGauss of the debug version using binarylibs we put on /sda/
```
The software installation path after compilation is **/sda/openGauss-server/dest**.
The compiled binary files are stored in **/sda/openGauss-server/dest/bin**.
Compilation log: **make_compile.log**
##### Compiling by Command
1. Run the following script to obtain the system version:
```
[user@linux openGauss-server]$ sh src/get_PlatForm_str.sh
```
> **NOTICE:**
>
> - The command output indicates the OSs supported by the openGauss. The OSs supported by the openGauss are centos7.6_x86_64 and openeuler_aarch64.
> - If **Failed** or another version is displayed, the openGauss does not support the current operating system.
2. Configure environment variables, add **____** based on the code download location, and replace *** with the result obtained in the previous step.
```
export CODE_BASE=________ # Path of the openGauss-server file
export BINARYLIBS=________ # Path of the binarylibs file
export GAUSSHOME=$CODE_BASE/dest/
export GCC_PATH=$BINARYLIBS/buildtools/***/gcc8.2/
export CC=$GCC_PATH/gcc/bin/gcc
export CXX=$GCC_PATH/gcc/bin/g++
export LD_LIBRARY_PATH=$GAUSSHOME/lib:$GCC_PATH/gcc/lib64:$GCC_PATH/isl/lib:$GCC_PATH/mpc/lib/:$GCC_PATH/mpfr/lib/:$GCC_PATH/gmp/lib/:$LD_LIBRARY_PATH
export PATH=$GAUSSHOME/bin:$GCC_PATH/gcc/bin:$PATH
```
For example, on CENTOS X86-64 platform, binarylibs directory is placed as the sibling directory of openGauss-server directory.
The following command can be executed under openGauss-server directory.
```
export CODE_BASE=`pwd`
export BINARYLIBS=`pwd`/../binarylibs
export GAUSSHOME=$CODE_BASE/dest/
export GCC_PATH=$BINARYLIBS/buildtools/centos7.6_x86_64/gcc8.2/
export CC=$GCC_PATH/gcc/bin/gcc
export CXX=$GCC_PATH/gcc/bin/g++
export LD_LIBRARY_PATH=$GAUSSHOME/lib:$GCC_PATH/gcc/lib64:$GCC_PATH/isl/lib:$GCC_PATH/mpc/lib/:$GCC_PATH/mpfr/lib/:$GCC_PATH/gmp/lib/:$LD_LIBRARY_PATH
export PATH=$GAUSSHOME/bin:$GCC_PATH/gcc/bin:$PATH
```
3. Select a version and configure it.
**debug** version:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS='-O0' --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-debug --enable-cassert --enable-thread-safety --without-readline --without-zlib
```
**release** version:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS="-O2 -g3" --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-thread-safety --without-readline --without-zlib
```
**memcheck** version:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS='-O0' --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-debug --enable-cassert --enable-thread-safety --without-readline --without-zlib --enable-memory-check
```
> **NOTICE:**
>
> - *[debug | release | memcheck]* indicates that three target versions are available.
> - On the ARM-based platform, **-D__USE_NUMA** needs to be added to **CFLAGS**.
> - On the **ARMv8.1** platform or a later version (for example, Kunpeng 920), **-D__ARM_LSE** needs to be added to **CFLAGS**.
> - If **binarylibs** is moved to **openGauss-server** or a soft link to **binarylibs** is created in **openGauss-server**, you do not need to specify the **--3rd** parameter. However, if you do so, please note that the file is easy to be deleted by the `git clean` command.
4. Run the following commands to compile openGauss:
```
[user@linux openGauss-server]$ make -sj
[user@linux openGauss-server]$ make install -sj
```
5. If the following information is displayed, the compilation and installation are successful:
```
openGauss installation complete.
```
The software installation path after compilation is **$GAUSSHOME**.
The compiled binary files are stored in **$GAUSSHOME/bin**.
### Compiling the Installation Package
Please read the chapter **Compiling by build.sh** first to understand the usage of build.sh and how to compile openGauss by using the script.
Now you can compile the installation package with just adding an option `-pkg`.
```
[user@linux openGauss-server]$ sh build.sh -m [debug | release | memcheck] -3rd [binarylibs path] -pkg
```
For example:
```
[user@linux openGauss-server]$ sh build.sh -pkg # Compile openGauss installation package of the release version. The binarylibs or its soft link must exist in the code directory. Otherwise, the operation fails.
[user@linux openGauss-server]$ sh build.sh -m debug -3rd /sda/binarylibs -pkg # Compile openGauss installation package of the debug version using binarylibs we put on /sda/
```
The generated installation package is stored in the **./package** directory.
Compilation log: **make_compile.log**
Installation package packaging log: **./package/make_package.log**
## Quick Start
See the [Quick Start](https://opengauss.org/en/docs/1.0.0/docs/Quickstart/Quickstart.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/1.0.0/docs/Releasenotes/Releasenotes.html).
## License
[MulanPSL-2.0](http://license.coscl.org.cn/MulanPSL2/)

620
README.md
View File

@ -1,303 +1,320 @@
![openGauss Logo](doc/openGauss-logo.png "openGauss logo")
- [What Is openGauss](#what-is-opengauss)
- [Installation](#installation)
- [Creating a Configuration File](#creating-a-configuration-file)
- [Initializing the Installation Environment](#initializing-the-installation-environment)
- [Executing Installation](#executing-installation)
- [Uninstalling the openGauss](#uninstalling-the-openGauss)
- [Compilation](#compilation)
- [Overview](#overview)
- [OS and Software Dependency Requirements](#os-and-software-dependency-requirements)
- [Downloading openGauss](#downloading-openGauss)
- [Compiling Third-Party Software](#compiling-third-party-software)
- [Compiling by build.sh](#compiling-by-build.sh)
- [Compiling by Command](#compiling-by-command)
- [Compiling the Installation Package](#compiling-the-installation-package)
- [Quick Start](#quick-start)
- [Docs](#docs)
- [Community](#community)
- [Governance](#governance)
- [Communication](#communication)
- [Contribution](#contribution)
- [Release Notes](#release-notes)
- [License](#license)
[English](./README.en.md) | 简体中文
## What Is openGauss
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.
<img src="doc/openGauss-architecture.png" alt="openGauss Architecture" width="600"/>
- [什么是openGauss](#什么是openGauss)
- [安装](#安装)
- [创建配置文件](#创建配置文件)
- [初始化安装环境](#初始化安装环境)
- [执行安装](#执行安装)
- [卸载openGauss](#卸载openGauss)
- [编译](#编译)
- [概述](#概述)
- [操作系统和软件依赖要求](#操作系统和软件依赖要求)
- [下载openGauss](#下载openGauss)
- [编译第三方软件](#编译第三方软件)
- [使用build.sh编译](#使用build编译)
- [使用命令编译](#使用命令编译)
- [编译安装包](#编译安装包)
- [快速入门](#快速入门)
- [文档](#文档)
- [社区](#社区)
- [治理](#治理)
- [交流](#交流)
- [贡献](#贡献)
- [发行说明](#发行说明)
- [许可证](许可证)
**High Performance**
## 什么是openGauss
openGauss breaks through the bottleneck of multi-core CPU, 2-way Kunpeng 128 core 1.5 million TPMC on disk-based row store and 3.5 million TPMC on MOT (Memory-Optimized Tables) Engine.
openGauss是一款开源的关系型数据库管理系统它具有多核高性能、全链路安全性、智能运维等企业级特性。
openGauss内核早期源自开源数据库PostgreSQL融合了华为在数据库领域多年的内核经验在架构、事务、存储引擎、优化器及ARM架构上进行了适配与优化。作为一个开源数据库期望与广泛的开发者共同构建一个多元化技术的开源数据库社区。
**Partitions**
<img src="doc/openGauss-architecture.png" alt="openGauss架构" width="600"/>
Divide key data structure shared by internal threads into different partitions to reduce lock access conflicts. For example, CLOG uses partition optimization to solve the bottleneck of ClogControlLock.
**高性能**
**NUMA Structure**
openGauss突破了多核CPU的瓶颈实现两路鲲鹏128核150万tpmC内存优化表MOT引擎达350万tpmC。
Malloc key data structures help reduce cross CPU access. The global PGPROC array is divided into several parts according to the number of NUMA nodes, solving the bottleneck of ProcArrayLock.
**数据分区**
**Binding Cores**
内部线程共享的关键数据结构进行数据分区减少加锁访问冲突。比如CLOG就采用分区优化解决ClogControlLock锁瓶颈。
Bind NIC interrupts to different cores and bind cores to different background threads to avoid performance instability due to thread migration between cores.
**NUMA化内核数据结构**
**ARM Optimization**
关键数据结构NUMA化分配减少跨CPU访问。比如全局PGPROC数组按照NUMA Node的数目分为多份分别在对应NUMA Node上申请内存。解决ProcArrayLock锁瓶颈。
Optimize atomic operations based on ARM platform LSE instructions, implementing efficient operation of critical sections.
**绑核优化**
**SQL Bypass**
把网络中断绑核和后台业务线程绑核区分开,避免运行线程在核间迁移造成的性能不稳定。
Optimize SQL execution process through SQL bypass, reducing CPU execution overhead.
**ARM指令优化**
**High Reliability**
结合ARM平台的原子操作lse进行优化实现关键互斥变量原子高效操作。
Under normal service loads, the RTO is less than 10 seconds, reducing the service interruption time caused by node failure.
**SQL BY PASS**
**Parallel Recovery**
通过SQL BY PASS优化SQL执行流程简化CPU执行开销。
When the Xlog is transferred to the standby node, the standby node flushes the Xlog to storage medium. At the meantime, the Xlog is sent to the redo recovery dispatch thread. The dispatch thread sends the Xlog to multiple parallel recovery threads to replay. Ensure that the redo speed of the standby node keeps up with the generation speed of the primary host. The standby node is ready in real time, which can be promoted to primary instantly.
**高可靠**
**MOT Engine (beta release)**
正常业务负载情况下RTO小于10秒降低节点故障导致的业务不可用时间。
The Memory-Optimized Tables (MOT) storage engine is a transactional rowstore optimized for many-core and large memory and delivering extreme OLTP performance and high resources utilization. With data and indexes stored totally in-memory, a NUMA-aware design, algorithms that eliminate lock and latch contention and query native compilation (JIT), MOT provides low latency data access and more efficient transaction execution. See MOT Engine documentation (https://opengauss.org/en/docs/1.0.0/docs/Developerguide/mot.html).
**并行恢复**
**Security**
主机日志传输到备机时备机日志落盘的同时发送给重做恢复分发线程分发线程根据日志类型和日志操作的数据页发给多个并行恢复线程进行日志重做保证备机的重做速度跟上主机日志的产生速度。这样备机实时处于ready状态从而实现瞬间故障切换。
openGauss supports account management, account authentication, account locking, password complexity check, privilege management and verification, transmission encryption, and operation audit, protecting service data security.
**Easy Operation and Maintenance**
**MOT引擎Beta发布**
openGauss integrates AI algorithms into databases, reducing the burden of database maintenance.
内存优化表MOT存储引擎是一个专为多核大内存优化的存储引擎具有极高的联机事务处理OLTP性能和资源利用率。MOT的数据和索引完全存储在内存中通过NUMA感知执行算法消除闩锁争用以及查询JIT本地编译提供低时延数据访问及高效事务执行。更多请参考[MOT引擎文档](https://opengauss.org/zh/docs/1.0.0/docs/Developerguide/%E5%86%85%E5%AD%98%E8%A1%A8%E7%89%B9%E6%80%A7.html)。
- **SQL Prediction**
**安全**
openGauss supports SQL execution time prediction based on collected historical performance data.
openGauss支持账号管理账号认证口令复杂度检查账号锁定权限管理和校验传输加密操作
审计等全方位的数据库安全能力,保护业务满足安全要求。
- **SQL Diagnoser**
**易运维**
openGauss supports the diagnoser for SQL execution statements, finding out slow queries in advance..
openGauss将AI算法集成到数据库中减少数据库维护的负担。
- **Automatic Parameter Adjustment**
- **SQL预测**
openGauss supports automatically adjusting database parameters, reducing the cost and time of parameter adjustment.
openGauss根据收集的历史性能数据进行编码和基于深度学习的训练及预测支持SQL执行时间预测。
## Installation
- **SQL诊断器**
### Creating a Configuration File
openGauss支持SQL执行语句的诊断器提前发现慢查询。
Before installing the openGauss, you need to create a configuration file. The configuration file in the XML format contains the information about the server where the openGauss is deployed, installation path, IP address, and port number. This file is used to guide how to deploy the openGauss. You need to configure the configuration file according to the actual deployment requirements.
- **参数自动调整**
The following describes how to create an XML configuration file based on the deployment solution of one primary node and one standby node.
The information of value is only an example. You can replace it as required. Each line of information is commented out.
openGauss通过机器学习方法自动调整数据库参数提高调参效率降低正确调参成本。
## 安装
### 创建配置文件
在安装openGauss之前需要创建clusterconfig.xml配置文件。XML文件包含部署openGauss的服务器信息、安装路径、IP地址以及端口号等。用于告知openGauss如何部署。用户需根据不同场配置对应的XML文件。
下面以一主一备的部署方案为例说明如何创建XML配置文件。
以下value取值信息仅为示例可自行替换。每行信息均有注释进行说明。
```
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<!-- Overall information -->
<CLUSTER>
<!-- Database name -->
<PARAM name="clusterName" value="Cluster_template" />
<!-- Database node name (hostname) -->
<PARAM name="nodeNames" value="node1_hostname,node2_hostname"/>
<!-- Database installation path -->
<PARAM name="gaussdbAppPath" value="/opt/huawei/install/app" />
<!-- Log directory -->
<PARAM name="gaussdbLogPath" value="/var/log/omm" />
<!-- Temporary file directory -->
<PARAM name="tmpMppdbPath" value="/opt/huawei/tmp"/>
<!-- Database tool directory -->
<PARAM name="gaussdbToolPath" value="/opt/huawei/install/om" />
<!--Directory of the core file of the database -->
<PARAM name="corePath" value="/opt/huawei/corefile"/>
<!-- Node IP addresses corresponding to the node names, respectively -->
<PARAM name="backIp1s" value="192.168.0.1,192.168.0.2"/>
</CLUSTER>
<!-- Information about node deployment on each server -->
<DEVICELIST>
<!-- Information about the node deployment on node1 -->
<DEVICE sn="node1_hostname">
<!-- Host name of node1 -->
<PARAM name="name" value="node1_hostname"/>
<!-- AZ where node1 is located and AZ priority -->
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- IP address of node1. If only one NIC is available for the server, set backIP1 and sshIP1 to the same IP address. -->
<PARAM name="backIp1" value="192.168.0.1"/>
<PARAM name="sshIp1" value="192.168.0.1"/>
<!--DBnode-->
<PARAM name="dataNum" value="1"/>
<!-- Database node port number -->
<PARAM name="dataPortBase" value="15400"/>
<!-- Data directory on the primary database node and data directories of standby nodes -->
<PARAM name="dataNode1" value="/opt/huawei/install/data/dn,node2_hostname,/opt/huawei/install/data/dn"/>
<!-- Number of nodes for which the synchronization mode is set on the database node -->
<PARAM name="dataNode1_syncNum" value="0"/>
</DEVICE>
<!-- Information about the node deployment on node2 -->
<DEVICE sn="node2_hostname">
<!-- Host name of node2 -->
<PARAM name="name" value="node2_hostname"/>
<!-- AZ where node2 is located and AZ priority -->
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- IP address of node2. If only one NIC is available for the server, set backIP1 and sshIP1 to the same IP address. -->
<PARAM name="backIp1" value="192.168.0.2"/>
<PARAM name="sshIp1" value="192.168.0.2"/>
</DEVICE>
</DEVICELIST>
<!-- openGauss整体信息 -->
<CLUSTER>
<!-- 数据库名称 -->
<PARAM name="clusterName" value="dbCluster" />
<!-- 数据库节点名称(hostname) -->
<PARAM name="nodeNames" value="node1,node2" />
<!-- 节点IP与nodeNames一一对应 -->
<PARAM name="backIp1s" value="192.168.0.11,192.168.0.12"/>
<!-- 数据库安装目录-->
<PARAM name="gaussdbAppPath" value="/opt/huawei/install/app" />
<!-- 日志目录-->
<PARAM name="gaussdbLogPath" value="/var/log/omm" />
<!-- 临时文件目录-->
<PARAM name="tmpMppdbPath" value="/opt/huawei/tmp"/>
<!--数据库工具目录-->
<PARAM name="gaussdbToolPath" value="/opt/huawei/install/om" />
<!--数据库core文件目录-->
<PARAM name="corePath" value="/opt/huawei/corefile"/>
<!-- openGauss类型此处示例为单机类型“single-inst”表示单机一主多备部署形态-->
<PARAM name="clusterType" value="single-inst"/>
</CLUSTER>
<!-- 每台服务器上的节点部署信息 -->
<DEVICELIST>
<!-- node1上的节点部署信息 -->
<DEVICE sn="1000001">
<!-- node1的hostname -->
<PARAM name="name" value="node1"/>
<!-- node1所在的AZ及AZ优先级 -->
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- 如果服务器只有一个网卡可用将backIP1和sshIP1配置成同一个IP -->
<PARAM name="backIp1" value="192.168.0.11"/>
<PARAM name="sshIp1" value="192.168.0.11"/>
<!--dbnode-->
<PARAM name="dataNum" value="1"/>
<!--DBnode端口号-->
<PARAM name="dataPortBase" value="26000"/>
<!--DBnode主节点上数据目录及备机数据目录-->
<PARAM name="dataNode1" value="/opt/huawei/install/data/db1,node2,/opt/huawei/install/data/db1"/>
<!--DBnode节点上设定同步模式的节点数-->
<PARAM name="dataNode1_syncNum" value="0"/>
</DEVICE>
<!-- node2上的节点部署信息其中“name”的值配置为主机名称hostname -->
<DEVICE sn="1000002">
<PARAM name="name" value="node2"/>
<PARAM name="azName" value="AZ1"/>
<PARAM name="azPriority" value="1"/>
<!-- 如果服务器只有一个网卡可用将backIP1和sshIP1配置成同一个IP -->
<PARAM name="backIp1" value="192.168.0.12"/>
<PARAM name="sshIp1" value="192.168.0.12"/>
</DEVICE>
</DEVICELIST>
</ROOT>
```
### Initializing the Installation Environment
### 初始化安装环境
After the openGauss configuration file is created, you need to run the gs_preinstall script to prepare the account and environment so that you can perform openGauss installation and management operations with the minimum permission, ensuring system security.
创建完openGauss配置文件后在执行安装前为了后续能以最小权限进行安装及openGauss管理操作保证系统安全性需要运行安装前置脚本gs_preinstall准备好安装用户及环境。
**Precautions**
安装前置脚本gs_preinstall可以协助用户自动完成如下的安装环境准备工作
- You must check the upper-layer directory permissions to ensure that the user has the read, write, and execution permissions on the installation package and configuration file directory.
- The mapping between each host name and IP address in the XML configuration file must be correct.
- Only user root is authorized to run the gs_preinstall command.
- 自动设置Linux内核参数以达到提高服务器负载能力的目的。这些参数直接影响数据库系统的运行状态请仅在确认必要时调整。
- 自动将openGauss配置文件、安装包拷贝到openGauss主机的相同目录下。
- openGauss安装用户、用户组不存在时自动创建安装用户以及用户组。
- 读取openGauss配置文件中的目录信息并创建将目录权限授予安装用户。
**Procedure**
**注意事项**
1. Log in to any host where the openGauss is to be installed as user root and create a directory for storing the installation package as planned.
- 用户需要检查上层目录权限,保证安装用户对安装包和配置文件目录读写执行的权限。
- xml文件中各主机的名称与IP映射配置正确。
- 只能使用root用户执行gs_preinstall命令。
**操作步骤**
1.以root用户登录待安装openGauss的任意主机并按规划创建存放安装包的目录。
```
mkdir -p /opt/software/openGauss
chmod 755 -R /opt/software
mkdir -p /opt/software/openGauss
chmod 755 -R /opt/software
```
> **NOTE:**
> **说明**
>
> - Do not create the directory in the home directory or subdirectory of any openGauss user because you may lack permissions for such directories.
> - The openGauss user must have the read and write permissions on the /opt/software/openGauss directory.
> - 不建议把安装包的存放目录规划到openGauss用户的家目录或其子目录下可能导致权限问题。
> - openGauss用户须具有/opt/software/openGauss目录的读写权限。
2. The release package is used as an example. Upload the installation package openGauss_x.x.x_PACKAGES_RELEASE.tar.gz and the configuration file clusterconfig.xml to the directory created in the previous step.
2.将安装包“openGauss-x.x.x-openEULER-64bit.tar.gz”和配置文件“clusterconfig.xml”都上传至上一步所创建的目录中。
3. Go to the directory for storing the uploaded software package and decompress the package.
3.在安装包所在的目录下解压安装包openGauss-x.x.x-openEULER-64bit.tar.gz。安装包解压后在/opt/software/openGauss目录下自动生成script目录。在script目录下生成gs_preinstall等OM工具脚本。
```
cd /opt/software/openGauss
tar -zxvf openGauss-x.x.x-openEULER-64bit.tar.gz
```
4.进入工具脚本目录。
```
cd /opt/software/openGauss
tar -zxvf openGauss_x.x.x_PACKAGES_RELEASE.tar.gz
cd /opt/software/openGauss/script
```
4. Decompress the openGauss-x.x.x-openEULER-64bit.tar.gz package.
5.如果是openEuler的操作系统执行如下命令打开performance.sh文件用#注释sysctl -w vm.min_free_kbytes=112640 &> /dev/null键入“ESC”键进入指令模式执行**:wq**保存并退出修改。
```
vi /etc/profile.d/performance.sh
```
6.为确保openssl版本正确执行预安装前请加载安装包中lib库。执行命令如下其中*{packagePath}*为用户安装包放置的路径,本示例中为/opt/software/openGauss。
```
tar -zxvf openGauss-x.x.x-openEULER-64bit.tar.gz
```
After the installation package is decompressed, the script subdirectory is automatically generated in /opt/software/openGauss. OM tool scripts such as gs_preinstall are generated in the script subdirectory.
5. Go to the directory for storing tool scripts.
```
cd /opt/software/openGauss/script
```
6. To ensure that the OpenSSL version is correct, load the lib library in the installation package before preinstallation. Run the following command. {packagePath} indicates the path where the installation package is stored. In this example, the path is /opt/software/openGauss.
```
export LD_LIBRARY_PATH={packagePath}/script/gspylib/clib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH={packagePath}/script/gspylib/clib:$LD_LIBRARY_PATH
```
7. To ensure successful installation, check whether the values of hostname and /etc/hostname are the same. During preinstallation, the host name is checked.
7.为确保成功安装,检查 hostname 与 /etc/hostname 是否一致。预安装过程中会对hostname进行检查。
8. Execute gs_preinstall to configure the installation environment. If the shared environment is used, add the --sep-env-file=ENVFILE parameter to separate environment variables to avoid mutual impact with other users. The environment variable separation file path is specified by users.
Execute gs_preinstall in interactive mode. During the execution, the mutual trust between users root and between clusteropenGauss users is automatically established.
8.使用gs_preinstall准备好安装环境。若为共用环境需加入--sep-env-file=ENVFILE参数分离环境变量避免与其他用户相互影响ENVFILE为用户自行指定的环境变量分离文件的路径。
执行如下命令即采用交互模式执行前置并在执行过程中自动创建root用户互信和openGauss用户互信
```
./gs_preinstall -U omm -G dbgrp -X /opt/software/openGauss/clusterconfig.xml
./gs_preinstall -U omm -G dbgrp -X /opt/software/openGauss/clusterconfig.xml
```
omm is the database administrator (also the OS user running the openGauss), dbgrp is the group name of the OS user running the openGauss, and /opt/software/ openGauss/clusterconfig.xml is the path of the openGauss configuration file. During the execution, you need to determine whether to establish mutual trust as prompted and enter the password of user root or the openGauss user.
omm为数据库管理员用户即运行openGauss的操作系统用户,dbgrp为运行openGauss的操作系统用户的组名/opt/software/ openGauss/clusterconfig.xml为openGauss的配置文件路径。执行过程中需要根据提示选择建立互信并输入root或openGauss用户的密码。
### Executing Installation
### 执行安装
After the openGauss installation environment is prepared by executing the pre-installation script, deploy openGauss based on the installation process.
执行前置脚本准备好openGauss安装环境之后按照启动安装过程部署openGauss。
**Prerequisites**
**前提条件**
- You have successfully executed the gs_preinstall script.
- All the server OSs and networks are functioning properly.
- You have checked that the locale parameter for each server is set to the same value.
- 已成功执行前置脚本gs_preinstall。
- 所有服务器操作系统和网络均正常运行。
- 用户需确保各个主机上的locale保持一致。
**Procedure**
**操作步骤**
1. (Optional) Check whether the installation package and openGauss configuration file exist in the planned directories. If no such package or file exists, perform the preinstallation again..
1.可选检查安装包和openGauss配置文件在规划路径下是否已存在如果没有重新执行预安装确保预安装成功再执行以下步骤。
2. Log in to any host of the openGauss and switch to the omm user.
2.登录到openGauss的主机并切换到omm用户。
```
su - omm
su - omm
```
> **NOTE:**
> **说明**
>
> - omm indicates the user specified by the -U parameter in the gs_preinstall script.
> - You need to execute the gs_install script as user omm specified in the gs_preinstall script. Otherwise, an execution error will be reported.
> - omm为gs_preinstall脚本中-U参数指定的用户。
> - 以上述omm用户执行gs_install脚本。否则会报执行错误。
3. Use gs_install to install the openGauss. If the openGauss is installed in environment variable separation mode, run the source command to obtain the environment variable separation file ENVFILE.
3.使用gs_install安装openGauss。若为环境变量分离的模式安装的集群需要source环境变量分离文件ENVFILE。
```
gs_install -X /opt/software/openGauss/clusterconfig.xml
gs_install -X /opt/software/openGauss/clusterconfig.xml
```
The password must meet the following complexity requirements:
/opt/software/openGauss/script/clusterconfig.xml为openGauss配置文件的路径。在执行过程中用户需根据提示输入数据库的密码密码具有一定的复杂度为保证用户正常使用该数据库请记住输入的数据库密码。
- Contain at least eight characters.
- Cannot be the same as the username, the current password (ALTER), or the current password in an inverted sequence.
- Contain at least three of the following: uppercase characters (A to Z), lowercase characters (a to z), digits (0 to 9), and other characters (limited to ~!@#$%^&*()-_=+\|[{}];:,<.>/?).
密码复杂度要求:
4. After the installation is successful, manually delete the trust between users root on the host, that is, delete the mutual trust file on each openGauss database node.
- 长度至少8个字符。
- 不能和用户名、当前密码ALTER、当前密码的倒序相同。
- 以下至少包含三类大写字母A~Z、小写字母a~z、数字0~9、其他字符仅限~!@#$%^&*()-_=+\|[{}];:,<.>/?)。
4.安装执行成功之后需要手动删除主机root用户的互信即删除openGauss数据库各节点上的互信文件。
```
rm -rf ~/.ssh
rm -rf ~/.ssh
```
### Uninstalling the openGauss
### 卸载openGauss
The process of uninstalling the openGauss includes uninstalling the openGauss and clearing the environment of the openGauss server.
卸载openGauss的过程包括卸载openGauss和清理openGauss服务器环境。
#### **Executing Uninstallation**
#### **执行卸载**
The openGauss provides an uninstallation script to help users uninstall the openGauss.
openGauss提供了卸载脚本帮助用户卸载openGauss。
**Procedure**
**操作步骤**
1. Log in as the OS user omm to the host where the CN is located.
1.以操作系统用户omm登录数据库主节点。
2. Execute the gs_uninstall script to uninstall the database cluster.
2.使用gs_uninstall卸载openGauss。
```
gs_uninstall --delete-data
gs_uninstall --delete-data
```
Alternatively, execute uninstallation on each openGauss node.
或者在openGauss中每个节点执行本地卸载。
```
gs_uninstall --delete-data -L
gs_uninstall --delete-data -L
```
#### **Deleting openGauss Configurations**
#### **一键式环境清理**
After the openGauss is uninstalled, execute the gs_postuninstall script to delete configurations from all servers in the openGauss if you do not need to re-deploy the openGauss using these configurations. These configurations are made by the gs_preinstall script.
**Prerequisites**
在openGauss卸载完成后如果不需要在环境上重新部署openGauss可以运行脚本gs_postuninstall对openGauss服务器上环境信息做清理。openGauss环境清理是对环境准备脚本gs_preinstall所做设置的清理。
**前提条件**
- The openGauss uninstallation task has been successfully executed.
- User root is trustworthy and available.
- Only user root is authorized to run the gs_postuninstall command.
- openGauss卸载执行成功。
- root用户互信可用。
- 只能使用root用户执行gs_postuninstall命令。
**Procedure**
**操作步骤**
1. Log in to the openGauss server as user root.
1.以root用户登录openGauss服务器。
2. Run the ssh Host name command to check whether mutual trust has been successfully established. Then, enter exit.
2.查看互信是否建成功,可以互相执行**ssh 主机名**。输入exit退出。
```
plat1:~ # ssh plat2
@ -308,158 +325,157 @@ After the openGauss is uninstalled, execute the gs_postuninstall script to delet
plat1:~ #
```
3. Go to the following path:
3.进入script路径下。
```
cd /opt/software/openGauss/script
```
4. Run the gs_postuninstall command to clear the environment. If the openGauss is installed in environment variable separation mode, run the source command to obtain the environment variable separation file ENVFILE.
4.使用gs_postuninstall进行清理。若为环境变量分离的模式安装的集群需要source环境变量分离文件ENVFILE。
```
./gs_postuninstall -U omm -X /opt/software/openGauss/clusterconfig.xml --delete-user --delete-group
```
Alternatively, locally use the gs_postuninstall tool to clear each openGauss node.
或者在openGauss中每个节点执行本地后置清理。
```
./gs_postuninstall -U omm -X /opt/software/openGauss/clusterconfig.xml --delete-user --delete-group -L
```
omm is the name of the OS user who runs the openGauss, and the path of the openGauss configuration file is /opt/software/openGauss/clusterconfig.xml.
If the cluster is installed in environment variable separation mode, delete the environment variable separation parameter ENV obtained by running the source command.
omm为运行openGauss的操作系统用户名/opt/software/openGauss/clusterconfig.xml为openGauss配置文件路径。
```
unset MPPDB_ENV_SEPARATE_PATH
```
若为环境变量分离的模式安装的集群需删除之前source的环境变量分离的env参数unset MPPDB_ENV_SEPARATE_PATH
5. Delete the mutual trust between the users root on each openGauss database node.
5.删除各openGauss数据库节点root用户互信。
## Compilation
## 编译
### Overview
### 概述
To compile openGauss, you need two components: openGauss-server and binarylibs.
编译openGauss需要openGauss-server和binarylibs两个组件。
- openGauss-server: main code of openGauss. You can obtain it from the open source community.
- openGauss-serveropenGauss的主要代码。可以从开源社区获取。
- binarylibs: third party open source software that openGauss depends on. You can obtain it by compiling the openGauss-third_party code or downloading from the open source community on which we have compiled a copy and uploaded it . The first method will be introduced in the following chapter.
- binarylibsopenGauss依赖的第三方开源软件你可以直接编译openGauss-third_party代码获取也可以从开源社区下载已经编译好的并上传的一个副本。
Before you compile openGauss, please check the OS and software dependency requirements.
在编译openGauss之前请检查操作系统和软件依赖要求。
You can compile openGauss by build.sh, a one-click shell tool, which we will introduce later, or compile by command. Also, an installation package is produced by build.sh.
openGauss可以通过一键式shell工具build.sh进行编译也可以通过命令进行编译。安装包由build.sh生成。
### OS and Software Dependency Requirements
### 操作系统和软件依赖要求
The following OSs are supported:
openGauss支持以下操作系统
- CentOS 7.6 (x86 architecture)
- CentOS 7.6x86架构
- openEuler-20.03-LTS (aarch64 architecture)
- openEuler-20.03-LTSaarch64架构
The following table lists the software requirements for compiling the openGauss.
以下表格列举了编译openGauss的软件要求。
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 | Recommended Version |
| ------------- | ------------------- |
| libaio-devel | 0.3.109-13 |
| flex | 2.5.31 or later |
| bison | 2.7-4 |
| ncurses-devel | 5.9-13.20130511 |
| glibc.devel | 2.17-111 |
| patch | 2.7.1-10 |
| lsb_release | 4.1 |
| 软件 | 推荐版本 |
| ------------- | --------------- |
| libaio-devel | 0.3.109-13 |
| flex | 2.5.31及以上版本 |
| bison | 2.7-4 |
| ncurses-devel | 5.9-13.20130511 |
| glibc.devel | 2.17-111 |
| patch | 2.7.1-10 |
| lsb_release | 4.1 |
### Downloading openGauss
### 下载openGauss
You can download openGauss-server and openGauss-third_party from open source community.
可以从开源社区下载openGauss-server和openGauss-third_party。
https://opengauss.org/zh/
From the following website, you can obtain the binarylibs we have compiled. Please unzip it and rename to **binarylibs** after you download.
可以通过以下网站获取编译好的binarylibs。下载后请解压缩并重命名为**binarylibs**。
https://opengauss.obs.cn-south-1.myhuaweicloud.com/1.0.0/openGauss-third_party_binarylibs.tar.gz
Now we have completed openGauss code, for example, we store it in following directories.
现在我们已经拥有完整的openGauss代码把它存储在以下目录中以sda为例
- /sda/openGauss-server
- /sda/binarylibs
- /sda/openGauss-third_party
### Compiling Third-Party Software
### 编译第三方软件
Before compiling the openGauss, compile and build the open-source and third-party software on which the openGauss depends. These open-source and third-party software is stored in the openGauss-third_party code repository and usually needs to be built only once. If the open-source software is updated, rebuild the software.
在编译openGauss之前需要先编译openGauss依赖的开源及第三方软件。这些开源及第三方软件存储在openGauss-third_party代码仓库中通常只需要构建一次。如果开源软件有更新需要重新构建软件。
You can also directly obtain the output file of the open-source software compilation and build from the **binarylibs** repository.
用户也可以直接从**binarylibs**库中获取开源软件编译和构建的输出文件。
If you want to compile third-party by yourself, please go to openGauss-third_party repository to see details.
如果你想自己编译第三方软件请到openGauss-third_party仓库查看详情。
After the preceding script is executed, the final compilation and build result is stored in the **binarylibs** directory at the same level as **openGauss-third_party**. These files will be used during the compilation of **openGauss-server**.
执行完上述脚本后,最终编译和构建的结果保存在与**openGauss-third_party**同级的**binarylibs**目录下。在编译**openGauss-server**时会用到这些文件。
### Compiling by build.sh
### 代码编译
build.sh in openGauss-server is an important script tool during compilation. It integrates software installation and compilation and product installation package compilation functions to quickly compile and package code.
##### 使用build.sh编译代码
The following table describes the parameters.
openGauss-server中的build.sh是编译过程中的重要脚本工具。该工具集成了软件安装编译和产品安装包编译功能可快速进行代码编译和打包。。
| Option | Default Value | Parameter | Description |
| :----- | :--------------------------- | :----------------------------- | :----------------------------------------------------------- |
| -h | Do not use this option. | - | Help menu. |
| -m | release | [debug \| release \| memcheck] | Selects the target version. |
| -3rd | ${Code directory}/binarylibs | [binarylibs path] | Specifies the path of binarylibs. The path must be an absolute path. |
| -pkg | Do not use this option. | - | Compresses the code compilation result into an installation package. |
| -nopt | Do not use this option. | - | On kunpeng platform, like 1616 version, without LSE optimized. |
参数说明请见以下表格。
> **NOTICE:**
| 选项 | 缺省值 | 参数 | 说明 |
| :---- | :--------------------------- | :------------------------------------- | :------------------------------------------------ |
| -h | 请勿使用此选项。 | - | 帮助菜单。 |
| -m | release | [debug &#124; release &#124; memcheck] | 选择目标版本。 |
| -3rd | ${Code directory}/binarylibs | [binarylibs path] | 指定binarylibs路径。该路径必须是绝对路径。 |
| -pkg | 请勿使用此选项。 | - | 将代码编译结果压缩至安装包。 |
| -nopt | 请勿使用此选项。 | - | 如果使用此功能则对鲲鹏平台的相关CPU不进行优化。 |
> **注意**
>
> 1. **-m [debug | release | memcheck]** indicates that three target versions can be selected:
> - **release**: indicates that the binary program of the release version is generated. During compilation of this version, the GCC high-level optimization option is configured to remove the kernel debugging code. This option is usually used in the generation environment or performance test environment.
> - **debug**: indicates that a binary program of the debug version is generated. During compilation of this version, the kernel code debugging function is added, which is usually used in the development self-test environment.
> - **memcheck**: indicates that a binary program of the memcheck version is generated. During compilation of this version, the ASAN function is added based on the debug version to locate memory problems.
> 2. **-3rd [binarylibs path]** is the path of **binarylibs**. By default, **binarylibs** exists in the current code folder. If **binarylibs** is moved to **openGauss-server** or a soft link to **binarylibs** is created in **openGauss-server**, you do not need to specify the parameter. However, if you do so, please note that the file is easy to be deleted by the **git clean** command.
> 3. Each option in this script has a default value. The number of options is small and the dependency is simple. Therefore, this script is easy to use. If the required value is different from the default value, set this parameter based on the actual requirements.
> - **-m [debug | release | memcheck]**表示有三个目标版本可以选择:
> - **release**生成release版本的二进制程序。此版本编译时通过配置GCC高级优化选项去除内核调试代码。此选项通常在生成环境或性能测试环境中使用。
> - **debug**表示生成debug版本的二进制程序。此版本编译时增加了内核代码调试功能一般用于开发自测环境。
> - **memcheck**表示生成memcheck版本的二进制程序。此版本编译时在debug版本的基础上增加了ASAN功能用于定位内存问题。
> - **-3rd [binarylibs path]**为**binarylibs**的路径。默认设置为当前代码文件夹下存在**binarylibs**,因此如果**binarylibs**被移至**openGauss-server**中,或者在**openGauss-server**中创建了到**binarylibs**的软链接,则不需要指定此参数。但请注意,这样做的话,该文件很容易被**git clean**命令删除。
> - 该脚本中的每个选项都有一个默认值。选项数量少,依赖简单。因此,该脚本易于使用。如果实际需要的参数值与默认值不同,请根据实际情况配置。
Now you know the usage of build.sh, so you can compile the openGauss-server by one command with build.sh.
现在你已经知晓build.sh的用法只需使用如下命令即可编译openGauss-server。
```
[user@linux openGauss-server]$ sh build.sh -m [debug | release | memcheck] -3rd [binarylibs path]
```
For example:
举例:
```
[user@linux openGauss-server]$ sh build.sh # Compile openGauss of the release version. The binarylibs or its soft link must exist in the code directory. Otherwise, the operation fails.
[user@linux openGauss-server]$ sh build.sh -m debug -3rd /sda/binarylibs # Compilate openGauss of the debug version using binarylibs we put on /sda/
[user@linux openGauss-server]$ sh build.sh # 编译安装release版本的openGauss。需代码目录下有binarylibs或者其软链接否则将会失败。
[user@linux openGauss-server]$ sh build.sh -m debug -3rd /sda/binarylibs # 编译安装debug版本的openGauss
```
The software installation path after compilation is **/sda/openGauss-server/dest**.
编译后的软件安装路径为:**/sda/openGauss-server/dest**
The compiled binary files are stored in **/sda/openGauss-server/dest/bin**.
编译后的二进制文件路径为:**/sda/openGauss-server/dest/bin**
Compilation log: **make_compile.log**
编译日志: **make_compile.log**
### Compiling by Command
##### 使用命令编译代码
1. Run the following script to obtain the system version:
1.执行以下脚本获取系统版本号:
```
[user@linux openGauss-server]$ sh src/get_PlatForm_str.sh
```
> **NOTICE:**
> **注意**
>
> - The command output indicates the OSs supported by the openGauss. The OSs supported by the openGauss are centos7.6_x86_64 and openeuler_aarch64.
> - If **Failed** or another version is displayed, the openGauss does not support the current operating system.
> - 命令回显信息即为openGauss支持的操作系统。目前openGauss支持的操作系统为centos7.6_x86_64和openeuler_aarch64。
> - 如果显示**Failed**或其他版本表示openGauss不支持当前操作系统。
2. Configure environment variables, add **____** based on the code download location, and replace *** with the result obtained in the previous step.
2.配置环境变量,根据代码下载位置添加**____**,并将***替换为上一步的结果。
```
export CODE_BASE=________ # Path of the openGauss-server file
@ -473,8 +489,8 @@ Compilation log: **make_compile.log**
```
For example, on CENTOS X86-64 platform, binarylibs directory is placed as the sibling directory of openGauss-server directory.
The following command can be executed under openGauss-server directory.
例如在CENTOS X86-64平台上binarylibs目录被作为openGauss-server目录的兄弟目录。
在openGauss-server目录下执行以下命令。
```
export CODE_BASE=`pwd`
@ -487,105 +503,105 @@ Compilation log: **make_compile.log**
export PATH=$GAUSSHOME/bin:$GCC_PATH/gcc/bin:$PATH
```
3. Select a version and configure it.
3.选择一个版本进行配置。
**debug** version:
**debug**版本:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS='-O0' --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-debug --enable-cassert --enable-thread-safety --without-readline --without-zlib
```
**release** version:
**release**版本:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS="-O2 -g3" --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-thread-safety --without-readline --without-zlib
```
**memcheck** version:
**memcheck**版本:
```
./configure --gcc-version=8.2.0 CC=g++ CFLAGS='-O0' --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-debug --enable-cassert --enable-thread-safety --without-readline --without-zlib --enable-memory-check
```
> **NOTICE:**
> **注意**
>
> 1. *[debug | release | memcheck]* indicates that three target versions are available.
> 2. On the ARM-based platform, **-D__USE_NUMA** needs to be added to **CFLAGS**.
> 3. On the **ARMv8.1** platform or a later version (for example, Kunpeng 920), **-D__ARM_LSE** needs to be added to **CFLAGS**.
> 4. If **binarylibs** is moved to **openGauss-server** or a soft link to **binarylibs** is created in **openGauss-server**, you do not need to specify the **--3rd** parameter. However, if you do so, please note that the file is easy to be deleted by the `git clean` command.
> 5. To build with mysql_fdw, add **--enable-mysql-fdw** when configure. Note that before build mysql_fdw, MariaDB's C client library is needed.
> 6. To build with oracle_fdw, add **--enable-oracle-fdw** when configure. Note that before build oracle_fdw, Oracle's C client library is needed.
> - *[debug | release | memcheck]*表示有三个目标版本可用。
> - 在ARM平台上需要把**-D__USE_NUMA**添加至**CFLAGS**中。
> - 在**ARMv8.1**及以上平台如鲲鹏920需要把**-D__ARM_LSE**添加至**CFLAGS**中。
> - 如果**binarylibs**被移至**openGauss-server**中,或者在**openGauss-server**中创建了到**binarylibs**的软链接,则不需要指定**--3rd**参数。但请注意,这样做的话,该文件很容易被`git clean`命令删除。
4. Run the following commands to compile openGauss:
4.执行以下命令编译openGauss
```
[user@linux openGauss-server]$ make -sj
[user@linux openGauss-server]$ make install -sj
```
5. If the following information is displayed, the compilation and installation are successful:
5.显示如下信息,表示编译和安装成功。
```
openGauss installation complete.
```
The software installation path after compilation is **$GAUSSHOME**.
- 编译后的软件安装路径为**$GAUSSHOME**。
The compiled binary files are stored in **$GAUSSHOME/bin**.
- 编译后的二进制文件存放路径为:**$GAUSSHOME/bin**。
### Compiling the Installation Package
Please read the chapter **Compiling by build.sh** first to understand the usage of build.sh and how to compile openGauss by using the script.
### 编译安装包
Now you can compile the installation package with just adding an option `-pkg`.
请先阅读[使用build.sh编译](#使用build.sh编译)章节了解build.sh的用法以及如何使用该脚本编译openGauss。
现在,只需添加一个-pkg选项就可以编译安装包。
```
[user@linux openGauss-server]$ sh build.sh -m [debug | release | memcheck] -3rd [binarylibs path] -pkg
```
For example:
举例:
```
[user@linux openGauss-server]$ sh build.sh -pkg # Compile openGauss installation package of the release version. The binarylibs or its soft link must exist in the code directory. Otherwise, the operation fails.
[user@linux openGauss-server]$ sh build.sh -m debug -3rd /sda/binarylibs -pkg # Compile openGauss installation package of the debug version using binarylibs we put on /sda/
sh build.sh -pkg # 生成release版本的openGauss安装包。需代码目录下有binarylibs或者其软链接否则将会失败。
sh build.sh -m debug -3rd /sdc/binarylibs -pkg # 生成debug版本的openGauss安装包
```
The generated installation package is stored in the **./package** directory.
- 生成的安装包存放目录:**./package**。
Compilation log: **make_compile.log**
- 编译日志: **make_compile.log**
Installation package packaging log: **./package/make_package.log**
- 安装包打包日志: **./package/make_package.log**
## Quick Start
See the [Quick Start](https://opengauss.org/en/docs/1.0.0/docs/Quickstart/Quickstart.html) to implement the image classification.
## 快速入门
## Docs
参考[快速入门](https://opengauss.org/zh/docs/1.0.0/docs/Quickstart/Quickstart.html)。
For more details about the installation guide, tutorials, and APIs, please see the [User Documentation](https://gitee.com/opengauss/docs).
## 文档
## Community
更多安装指南、教程和API请参考[用户文档](https://gitee.com/opengauss/docs)。
### Governance
## 社区
Check out how openGauss implements open governance [works](https://gitee.com/opengauss/community/blob/master/governance.md).
### 治理
### Communication
查看openGauss是如何实现开放[治理](https://gitee.com/opengauss/community/blob/master/governance.md)。
- 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
- WeLink开发者的交流平台。
- IRC频道`#opengauss-meeting`(仅用于会议纪要)。
- 邮件列表https://opengauss.org/zh/community/onlineCommunication.html
Welcome contributions. See our [Contributor](https://opengauss.org/en/contribution.html) for more details.
## 贡献
## Release Notes
欢迎大家来参与贡献。详情请参阅我们的[社区贡献](https://opengauss.org/zh/contribution.html)。
For the release notes, see our [RELEASE](https://opengauss.org/en/docs/1.0.0/docs/Releasenotes/Releasenotes.html).
## 发行说明
## License
请参见[发行说明](https://opengauss.org/zh/docs/1.0.0/docs/Releasenotes/Releasenotes.html)。
## 许可证
[MulanPSL-2.0](http://license.coscl.org.cn/MulanPSL2/)

View File

@ -50,8 +50,6 @@
PG_MODULE_MAGIC;
/* These must be available to pg_dlsym() */
extern "C" PG_FUNCTION_INFO_V1(_PG_init);
extern "C" PG_FUNCTION_INFO_V1(_PG_output_plugin_init);
extern "C" void _PG_init(void);
extern "C" void _PG_output_plugin_init(OutputPluginCallbacks* cb);

View File

@ -17,3 +17,6 @@ top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
exclude_option=-fPIE
override CPPFLAGS := $(filter-out $(exclude_option),$(CPPFLAGS))

View File

@ -1936,3 +1936,4 @@ static int comp_location(const void* a, const void* b)
else
return 0;
}

View File

@ -33,8 +33,6 @@
PG_MODULE_MAGIC;
/* These must be available to pg_dlsym() */
extern "C" PG_FUNCTION_INFO_V1(_PG_init);
extern "C" PG_FUNCTION_INFO_V1(_PG_output_plugin_init);
extern "C" void _PG_init(void);
extern "C" void _PG_output_plugin_init(OutputPluginCallbacks* cb);

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,34 +1,5 @@
# Architecture And Os Version
# openGauss on Docker
Sample Docker build files to facilitate installation, configuration, and environment setup for DevOps users. For more information about openGasuss please see the [openGauss Online Documentation](https://opengauss.org/zh/docs/1.0.0/docs/Quickstart/Quickstart.html).
x86-64 CentOS7.6
ARM64 openEuler 20.03 LTS
# Build Image
```console
docker build -t opengauss:1.0 .
```
# Start Instance
```console
$ docker run --name opengauss --privileged=true -d -e GS_PASSWORD=secretpassword@123 opengauss:1.0
```
# Connect To The Container Database From Os
```console
$ docker run name opengauss privileged=true d e GSPASSWORD=secretpassword@123 \
p8888:5432 opengauss:1.0 gsql -d postgres -U gaussdb -W'secretpassword@123' \
-h your-host-ip -p8888
```
# Persist Data
```console
$ docker run --name opengauss --privileged=true -d -e GS_PASSWORD=secretpassword@123 \
-v /opengauss:/var/lib/opengauss opengauss:1.0
```
# Todo
primary standby install
## SingleInstance
Provides Docker build files to create an openGasuss Single Instance Docker image. For more details, see [SingleInstance/README.md](./SingleInstance/README.md).

View File

@ -0,0 +1,8 @@
# About Opengauss
openGauss is an open source relational database management system that is released with the Mulan PSL v2. with the kernel derived from PostgreSQL, openGauss is built on Huawei's years of experience in the database field and continuously provides competitive features tailored to enterprise-class scenarios. In addition, openGauss is an open source database platform that encourages community contribution and collaboration.
# How To Run Opengauss On Docker
You may read the English installation guide [openGauss-in-Docker-container-installation-guide.md](https://gitee.com/lee1002/docs/blob/master/content/en/docs/installation/openGauss-in-Docker-container-installation-guide.md
), and [中文安装指南](https://gitee.com/lee1002/docs/blob/master/content/zh/docs/installation/openGauss容器版本安装指南.md) for details.

View File

@ -0,0 +1 @@
369bbc8229d0526b8df454f76d244397 openGauss-1.0.0-CentOS-64bit.tar.bz2

View File

@ -35,10 +35,10 @@ RUN mkdir /docker-entrypoint-initdb.d
ENV PGDATA /var/lib/opengauss/data
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh;ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh;ln -s /usr/local/bin/entrypoint.sh / # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 5432
CMD ["gaussdb"]

View File

@ -0,0 +1,178 @@
#!/bin/bash -e
usage() {
cat << EOF
Usage: buildDockerImage.sh -v [version] [-i] [Docker build option]
Builds a Docker Image for openGauss
Parameters:
-v: version to build
Choose one of: $(for i in $(ls -d */); do echo -n "${i%%/} "; done)
-i: ignores the MD5 checksums
LICENSE UPL 1.0
EOF
}
# Validate packages
checksumPackages() {
if hash md5sum 2>/dev/null; then
echo "Checking if required packages are present and valid..."
if ! md5sum -c "Checksum"; then
echo "MD5 for required packages to build this image did not match!"
echo "Make sure to download missing files in folder $VERSION."
exit 1;
fi
else
echo "Ignored MD5 sum, 'md5sum' command not available.";
fi
}
# Check Docker version
checkDockerVersion() {
# Get Docker Server version
echo "Checking Docker version."
DOCKER_VERSION=$(docker version --format '{{.Server.Version | printf "%.5s" }}'|| exit 0)
# Remove dot in Docker version
DOCKER_VERSION=${DOCKER_VERSION//./}
if [ -z "$DOCKER_VERSION" ]; then
# docker could be aliased to podman and errored out (https://github.com/containers/libpod/pull/4608)
checkPodmanVersion
elif [ "$DOCKER_VERSION" -lt "${MIN_DOCKER_VERSION//./}" ]; then
echo "Docker version is below the minimum required version $MIN_DOCKER_VERSION"
echo "Please upgrade your Docker installation to proceed."
exit 1;
fi;
}
##############
#### MAIN ####
##############
# Parameters
VERSION="1.0.0"
SKIPMD5=0
DOCKEROPS=""
MIN_DOCKER_VERSION="17.09"
DOCKERFILE="Dockerfile"
if [ "$#" -eq 0 ]; then
usage;
exit 1;
fi
while getopts "hesxiv:o:" optname; do
case "$optname" in
"h")
usage
exit 0;
;;
"i")
SKIPMD5=1
;;
"v")
VERSION="$OPTARG"
;;
"o")
DOCKEROPS="$OPTARG"
;;
"?")
usage;
exit 1;
;;
*)
# Should not occur
echo "Unknown error while processing options inside buildDockerImage.sh"
;;
esac
done
checkDockerVersion
# Which Dockerfile should be used?
if [ "$VERSION" == "12.1.0.2" ] || [ "$VERSION" == "11.2.0.2" ] || [ "$VERSION" == "18.4.0" ]; then
DOCKERFILE="$DOCKERFILE"
fi;
# Oracle Database Image Name
IMAGE_NAME="opengauss:$VERSION"
# Go into version folder
cd "$VERSION" || {
echo "Could not find version directory '$VERSION'";
exit 1;
}
if [ ! "$SKIPMD5" -eq 1 ]; then
checksumPackages
else
echo "Ignored MD5 checksum."
fi
echo "=========================="
echo "DOCKER info:"
docker info
echo "=========================="
# Proxy settings
PROXY_SETTINGS=""
if [ "${http_proxy}" != "" ]; then
PROXY_SETTINGS="$PROXY_SETTINGS --build-arg http_proxy=${http_proxy}"
fi
if [ "${https_proxy}" != "" ]; then
PROXY_SETTINGS="$PROXY_SETTINGS --build-arg https_proxy=${https_proxy}"
fi
if [ "${ftp_proxy}" != "" ]; then
PROXY_SETTINGS="$PROXY_SETTINGS --build-arg ftp_proxy=${ftp_proxy}"
fi
if [ "${no_proxy}" != "" ]; then
PROXY_SETTINGS="$PROXY_SETTINGS --build-arg no_proxy=${no_proxy}"
fi
if [ "$PROXY_SETTINGS" != "" ]; then
echo "Proxy settings were found and will be used during the build."
fi
# ################## #
# BUILDING THE IMAGE #
# ################## #
echo "Building image '$IMAGE_NAME' ..."
# BUILD THE IMAGE (replace all environment variables)
BUILD_START=$(date '+%s')
docker build --force-rm=true --no-cache=true \
$DOCKEROPS $PROXY_SETTINGS \
-t $IMAGE_NAME -f $DOCKERFILE . || {
echo ""
echo "ERROR: Oracle Database Docker Image was NOT successfully created."
echo "ERROR: Check the output and correct any reported problems with the docker build operation."
exit 1
}
# Remove dangling images (intermitten images with tag <none>)
yes | docker image prune > /dev/null
BUILD_END=$(date '+%s')
BUILD_ELAPSED=`expr $BUILD_END - $BUILD_START`
echo ""
echo ""
cat << EOF
openGauss Docker Image $VERSION is ready to be extended:
--> $IMAGE_NAME
Build completed in $BUILD_ELAPSED seconds.
EOF

View File

@ -303,6 +303,10 @@ max_process_memory|int|2097152,2147483647|kB|NULL|
session_statistics_memory|int|5120,1073741823|kB|NULL|
session_history_memory|int|10240,1073741823|kB|NULL|
max_query_retry_times|int|0,20|NULL|NULL|
max_replication_slots|int|0,262143|NULL|NULL|
enable_slot_log|bool|0,0|NULL|NULL|
max_changes_in_memory|int|1,2147483647|NULL|NULL|
max_cached_tuplebufs|int|1,2147483647|NULL|NULL|
max_stack_depth|int|100,2147483647|kB|NULL|
max_standby_archive_delay|int|-1,2147483647|ms|'-1' means to permit backup machine waits until the query of conflict is completed.|
max_standby_streaming_delay|int|-1,2147483647|ms|NULL|
@ -519,6 +523,7 @@ numa_distribute_mode|string|0,0|NULL|NULL|
defer_csn_cleanup_time|int|0,2147483647|ms|NULL|
tcp_recv_timeout|int|0,86400|s|Specify the receiving timeouts until reporting an error.|
max_inner_tool_connections|int|1,8388607|NULL|NULL|
max_keep_log_seg|int|0,2147483647|NULL|NULL|
[gtm]
nodename|string|0,0|NULL|Name of this GTM/GTM-Standby.|
port|int|1,65535|NULL|Listen Port of GTM or GTM standby server.|
@ -658,6 +663,7 @@ cstore_buffers|int|16384,1073741823|kB|NULL|
udfworkermemhardlimit|int|0,2147483647|kB|Sets the hard memory limit to be used for fenced UDF.|
wal_buffers|int|-1,262143|kB|Every time a transaction is committed, the contents of WAL buffers are written to disk, it is set to a large value will not bring significant performance gains. If you set it to hundreds of megabytes, you may have written to the disk to improve performance on the server a lot of real-time transaction commits. According to experience, the default value is sufficient for most situations.|
max_wal_senders|int|0,8388607|NULL|Check whether the new value of max_wal_senders is less than max_connections and wal_level is archive or hot_standby, otherwise the gaussdb will start failed.|
max_replication_slots|int|0,262143|NULL|NULL|
autovacuum_freeze_max_age|int64|100000,576460752303423487|NULL|NULL|
autovacuum_max_workers|int|0,8388607|NULL|NULL|
track_activity_query_size|int|100,102400|NULL|NULL|

View File

@ -1035,8 +1035,9 @@ static PGPing test_postmaster_connection(pgpid_t pm_pid, bool do_checkpoint, str
_("could not stat file gaussdb_state_file %s: %s\n"),
gaussdb_state_file,
strerror(errno));
} else {
if (beforeStat.st_mtime != afterStat.st_mtime) {
} else if (errno != ENOENT) {
if (beforeStat.st_mtim.tv_sec != afterStat.st_mtim.tv_sec ||
beforeStat.st_mtim.tv_nsec != afterStat.st_mtim.tv_nsec) {
nRet = memset_s(&state, sizeof(state), 0, sizeof(state));
securec_check_c(nRet, "\0", "\0");
ReadDBStateFile(&state);
@ -3410,7 +3411,7 @@ static void do_help(void)
" (PostgreSQL server executable) or gs_initdb\n"));
printf(_(" -p PATH-TO-POSTGRES normally not necessary\n"));
printf(_("\nOptions for stop or restart:\n"));
printf(_(" -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
printf(_(" -m, --mode=MODE MODE can be \"fast\", or \"immediate\"\n"));
printf(_("\nOptions for restore:\n"));
printf(_(" --remove-backup Remove the pg_rewind_bak dir after restore with \"restore\" command\n"));
#ifdef ENABLE_MULTIPLE_NODES
@ -3420,7 +3421,6 @@ static void do_help(void)
printf(_(" -n NAME patch name, NAME should be patch name with path\n"));
#endif
printf(_("\nShutdown modes are:\n"));
printf(_(" smart quit with fast shutdown on primary, and recovery done on standby\n"));
printf(_(" fast quit directly, with proper shutdown\n"));
printf(_(" immediate quit without complete shutdown; will lead to recovery on restart\n"));
@ -3479,12 +3479,7 @@ static void do_help(void)
static void set_mode(char* modeopt)
{
if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0) {
shutdown_mode = SMART_MODE;
stop_mode = "smart";
switch_mode = SmartDemote;
sig = SIGTERM;
} else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0) {
if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0) {
shutdown_mode = FAST_MODE;
stop_mode = "fast";
switch_mode = FastDemote;

View File

@ -2526,6 +2526,10 @@ static void makeTableDataInfo(TableInfo* tbinfo, bool boids)
if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED && no_unlogged_table_data)
return;
/* Don't dump data in global temp table/sequence */
if (tbinfo->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
return;
/* Check that the data is not explicitly excluded */
if (simple_oid_list_member(&tabledata_exclude_oids, tbinfo->dobj.catId.oid))
return;
@ -4694,7 +4698,7 @@ AggInfo* getAggregates(Archive* fout, int* numAggs)
"(%s proowner) AS rolname, "
"proacl AS aggacl "
"FROM pg_proc p "
"WHERE proisagg AND ("
"WHERE prokind = 'a' AND ("
"pronamespace != "
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog')",
@ -4716,7 +4720,7 @@ AggInfo* getAggregates(Archive* fout, int* numAggs)
"(%s proowner) AS rolname, "
"proacl AS aggacl "
"FROM pg_proc "
"WHERE proisagg "
"WHERE prokind = 'a' "
"AND pronamespace != "
"(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
username_subquery);
@ -4862,7 +4866,7 @@ FuncInfo* getFuncs(Archive* fout, int* numFuncs)
"pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc p "
"WHERE NOT proisagg AND ("
"WHERE prokind != 'a' AND ("
"pronamespace != "
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog')",
@ -11118,7 +11122,7 @@ static void dumpFunc(Archive* fout, FuncInfo* finfo)
char* proallargtypes = NULL;
char* proargmodes = NULL;
char* proargnames = NULL;
char* proiswindow = NULL;
char* prokind = NULL;
char* provolatile = NULL;
char* proisstrict = NULL;
char* prosecdef = NULL;
@ -11171,7 +11175,7 @@ static void dumpFunc(Archive* fout, FuncInfo* finfo)
"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
"pg_catalog.pg_get_function_result(oid) AS funcresult, "
"proiswindow, provolatile, proisstrict, prosecdef, "
"prokind, provolatile, proisstrict, prosecdef, "
"proleakproof, proconfig, procost, prorows, "
"%s, "
"%s, "
@ -11192,7 +11196,7 @@ static void dumpFunc(Archive* fout, FuncInfo* finfo)
funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
proallargtypes = proargmodes = proargnames = NULL;
proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
@ -11303,7 +11307,7 @@ static void dumpFunc(Archive* fout, FuncInfo* finfo)
appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
if (proiswindow[0] == 't')
if (PROC_IS_WIN(prokind[0]))
appendPQExpBuffer(q, " WINDOW");
if (provolatile[0] != PROVOLATILE_VOLATILE) {
@ -16035,9 +16039,17 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo)
if (tbinfo->parttype == PARTTYPE_PARTITIONED_RELATION) {
appendPQExpBuffer(q, "CREATE %s %s", reltypename, fmtId(tbinfo->dobj.name));
} else {
const char *tableType = nullptr;
if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED) {
tableType = "UNLOGGED ";
} else if (tbinfo->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
tableType = "GLOBAL TEMPORARY ";
} else {
tableType = "";
}
appendPQExpBuffer(q,
"CREATE %s%s %s",
tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ? "UNLOGGED " : "",
tableType,
reltypename,
fmtId(tbinfo->dobj.name));
}
@ -16715,7 +16727,9 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo)
* attislocal correctly, plus fix up any inherited CHECK constraints.
* Analogously, we set up typed tables using ALTER TABLE / OF here.
*/
if (binary_upgrade && ((tbinfo->relkind == RELKIND_RELATION) || (tbinfo->relkind == RELKIND_FOREIGN_TABLE))) {
if (binary_upgrade &&
((tbinfo->relkind == RELKIND_RELATION) || (tbinfo->relkind == RELKIND_FOREIGN_TABLE)) &&
tbinfo->relpersistence != RELPERSISTENCE_GLOBAL_TEMP) {
for (j = 0; j < tbinfo->numatts; j++) {
if (tbinfo->attisdropped[j]) {
appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");

View File

@ -101,7 +101,7 @@ bool describeAggregates(const char* pattern, bool verbose, bool showSystem)
" pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
"FROM pg_catalog.pg_proc p\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
"WHERE p.proisagg\n",
"WHERE p.prokind = 'a'\n",
gettext_noop("Description"));
if (!showSystem && (pattern == NULL))
@ -264,8 +264,8 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
" pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
" pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
" CASE\n"
" WHEN p.proisagg THEN '%s'\n"
" WHEN p.proiswindow THEN '%s'\n"
" WHEN p.prokind = 'a' THEN '%s'\n"
" WHEN p.prokind = 'w' THEN '%s'\n"
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
" ELSE '%s'\n"
"END as \"%s\"",
@ -311,7 +311,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
" ), ', ')\n"
" END AS \"%s\",\n"
" CASE\n"
" WHEN p.proisagg THEN '%s'\n"
" WHEN p.prokind = 'a' THEN '%s'\n"
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
" ELSE '%s'\n"
" END AS \"%s\"",
@ -328,7 +328,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
" pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
" CASE\n"
" WHEN p.proisagg THEN '%s'\n"
" WHEN p.prokind = 'a' THEN '%s'\n"
" WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
" ELSE '%s'\n"
" END AS \"%s\"",
@ -384,7 +384,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
appendPQExpBuffer(&buf, "WHERE ");
have_where = true;
}
appendPQExpBuffer(&buf, "NOT p.proisagg\n");
appendPQExpBuffer(&buf, "p.prokind != 'a'\n");
}
if (!showTrigger) {
if (have_where) {
@ -402,7 +402,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
appendPQExpBuffer(&buf, "WHERE ");
have_where = true;
}
appendPQExpBuffer(&buf, "NOT p.proiswindow\n");
appendPQExpBuffer(&buf, "p.prokind != 'w'\n");
}
} else {
bool needs_or = false;
@ -411,7 +411,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
have_where = true;
/* Note: at least one of these must be true ... */
if (showAggregate) {
appendPQExpBuffer(&buf, "p.proisagg\n");
appendPQExpBuffer(&buf, "p.prokind = 'a'\n");
needs_or = true;
}
if (showTrigger) {
@ -425,7 +425,7 @@ bool describeFunctions(const char* functypes, const char* pattern, bool verbose,
if (needs_or) {
appendPQExpBuffer(&buf, " OR ");
}
appendPQExpBuffer(&buf, "p.proiswindow\n");
appendPQExpBuffer(&buf, "p.prokind = 'w'\n");
needs_or = true;
}
appendPQExpBuffer(&buf, " )\n");

View File

@ -198,7 +198,7 @@ static const SchemaQuery Query_for_list_of_aggregates = {
/* catname */
"pg_catalog.pg_proc p",
/* selcondition */
"p.proisagg",
"p.prokind",
/* viscondition */
"pg_catalog.pg_function_is_visible(p.oid)",
/* namespace */

View File

@ -21,7 +21,8 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o pg_object.o\
pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o pg_synonym.o\
pg_type.o pgxc_class.o storage.o toasting.o pg_job.o pg_partition.o pg_hashbucket.o cstore_ctlg.o dfsstore_ctlg.o pg_builtin_proc.o
pg_type.o pgxc_class.o storage_gtt.o storage.o toasting.o pg_job.o pg_partition.o \
pg_hashbucket.o cstore_ctlg.o dfsstore_ctlg.o pg_builtin_proc.o
BKIFILES = postgres.bki postgres.description postgres.shdescription

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,7 @@
#include "commands/directory.h"
#include "cstore.h"
#include "storage/custorage.h"
#include "threadpool/threadpool.h"
#include "catalog/pg_resource_pool.h"
#include "catalog/pg_workload_group.h"
#include "catalog/pg_app_workloadgroup_mapping.h"
@ -1049,9 +1050,22 @@ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
char* rpath = NULL;
int fd;
bool collides = false;
BackendId backend;
switch (relpersistence) {
case RELPERSISTENCE_GLOBAL_TEMP:
backend = BackendIdForTempRelations;
break;
case RELPERSISTENCE_TEMP:
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);
return InvalidOid; /* placate compiler */
}
//@Temp Table. we now use same storage as unlogged table for temp table,
// so backendID is no need.
/* This logic should match relation_init_physical_addr */
rnode.node.spcNode = ConvertToRelfilenodeTblspcOid(reltablespace);
rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : u_sess->proc_cxt.MyDatabaseId;
@ -1061,7 +1075,7 @@ Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
* that properly here to make sure that any collisions based on filename
* are properly detected.
*/
rnode.backend = InvalidBackendId;
rnode.backend = backend;
do {
CHECK_FOR_INTERRUPTS();

View File

@ -31,6 +31,7 @@
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xact.h"
@ -62,6 +63,7 @@
#include "catalog/pg_type_fn.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/storage_gtt.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/typecmds.h"
@ -109,8 +111,9 @@
#endif
static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions, int2vector* bucketcol, bool ispartrel);
static oidvector* buldIntervalTablespace(IntervalPartitionDefState* intervalPartDef);
Oid reloftype, Oid relowner, char relkind, char relpersistence, Datum relacl, Datum reloptions,
int2vector* bucketcol, bool ispartrel);
static oidvector* BuildIntervalTablespace(const IntervalPartitionDefState* intervalPartDef);
static void deletePartitionTuple(Oid part_id);
static void addNewPartitionTuplesForPartition(Relation pg_partition_rel, Oid relid, List *filenodelist, Oid reltablespace,
Oid bucketOid, PartitionState* partTableState, Oid ownerid, Datum reloptions, const TupleDesc tupledesc);
@ -405,7 +408,8 @@ Form_pg_attribute SystemAttributeByName(const char* attname, bool relhasoids)
*/
Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid relfilenode,
Oid bucketOid, TupleDesc tupDesc, char relkind, char relpersistence, bool partitioned_relation, bool rowMovement,
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid)
bool shared_relation, bool mapped_relation, bool allow_system_table_mods, int8 row_compress, Oid ownerid,
bool skip_create_storage)
{
bool create_storage = false;
Relation rel;
@ -511,6 +515,9 @@ Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, O
if (u_sess->attr.attr_common.IsInplaceUpgrade && !u_sess->upg_cxt.new_catalog_need_storage)
create_storage = false;
if (skip_create_storage) {
create_storage = false;
}
/*
* Have the storage manager create the relation's disk file, if needed.
*
@ -519,7 +526,7 @@ Relation heap_create(const char* relname, Oid relnamespace, Oid reltablespace, O
*/
if (create_storage) {
RelationOpenSmgr(rel);
RelationCreateStorage(rel->rd_node, relpersistence, ownerid, bucketOid);
RelationCreateStorage(rel->rd_node, relpersistence, ownerid, bucketOid, rel);
}
if (RelationUsesSpaceType(rel->rd_rel->relpersistence) == SP_TEMP) {
@ -1007,7 +1014,8 @@ void InsertPgClassTuple(
* --------------------------------
*/
static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions, int2vector* bucketcol, bool ispartrel)
Oid reloftype, Oid relowner, char relkind, char relpersistence, Datum relacl, Datum reloptions,
int2vector* bucketcol, bool ispartrel)
{
Form_pg_class new_rel_reltup;
@ -1039,6 +1047,7 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, O
new_rel_reltup->relallvisible = 0;
break;
}
/* Initialize relfrozenxid */
if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE) {
/*
@ -1056,6 +1065,12 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, O
*/
new_rel_reltup->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
}
/* global temp table not remember transaction info in catalog */
if (relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
new_rel_reltup->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
}
new_rel_reltup->relowner = relowner;
new_rel_reltup->reltype = new_type_oid;
new_rel_reltup->reloftype = reloftype;
@ -1927,7 +1942,8 @@ Oid heap_create_with_catalog(const char* relname, Oid relnamespace, Oid reltable
mapped_relation,
allow_system_table_mods,
row_compress,
ownerid);
ownerid,
false);
/* Recode the table or other object in pg_class create time. */
PgObjectType objectType = GetPgObjectTypePgClass(relkind);
@ -2067,6 +2083,7 @@ Oid heap_create_with_catalog(const char* relname, Oid relnamespace, Oid reltable
reloftypeid,
ownerid,
relkind,
relpersistence,
PointerGetDatum(relacl),
reloptions,
bucketcol,
@ -2700,6 +2717,15 @@ void heap_drop_with_catalog(Oid relid)
heapDropPartitionTable(rel);
}
/* We allow to drop global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (is_other_backend_use_gtt(RelationGetRelid(rel)))
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop global temporary table %s when other backend attached it.",
RelationGetRelationName(rel))));
}
/*
* When dropping temp objects, we need further check whether current datanode is
* suffered from an unclean shutdown without gsql reconnect, as in this case the
@ -3602,7 +3628,7 @@ void RemoveStatistics(Oid relid, AttrNumber attnum)
* The routine will truncate and then reconstruct the indexes on
* the specified relation. Caller must hold exclusive lock on rel.
*/
static void RelationTruncateIndexes(Relation heapRelation)
static void RelationTruncateIndexes(Relation heapRelation, LOCKMODE lockmode)
{
ListCell* indlist = NULL;
@ -3613,7 +3639,7 @@ static void RelationTruncateIndexes(Relation heapRelation)
IndexInfo* indexInfo = NULL;
/* Open the index relation; use exclusive lock, just to be sure */
currentIndex = index_open(indexId, AccessExclusiveLock);
currentIndex = index_open(indexId, lockmode);
/* Fetch info needed for index_build */
indexInfo = BuildIndexInfo(currentIndex);
@ -3628,7 +3654,7 @@ static void RelationTruncateIndexes(Relation heapRelation)
}
/* truncate psort relation */
if (unlikely(currentIndex->rd_rel->relam == PSORT_AM_OID)) {
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(psort_rel);
heap_close(psort_rel, NoLock);
}
@ -3660,8 +3686,14 @@ void heap_truncate(List* relids)
foreach (cell, relids) {
Oid rid = lfirst_oid(cell);
Relation rel;
LOCKMODE lockmode = AccessExclusiveLock;
rel = heap_open(rid, AccessExclusiveLock);
/* truncate global temp table only need RowExclusiveLock */
if (get_rel_persistence(rid) == RELPERSISTENCE_GLOBAL_TEMP) {
lockmode = RowExclusiveLock;
}
rel = heap_open(rid, lockmode);
relations = lappend(relations, rel);
}
@ -3724,7 +3756,7 @@ static void heap_truncate_one_rel_for_bucket(Relation rel, Partition part)
if (OidIsValid(toastOid)) {
toastBucketRel = bucketGetRelation(rel, NULL, bucketlist->values[i]);
RelationTruncate(toastBucketRel, 0);
RelationTruncateIndexes(toastBucketRel);
RelationTruncateIndexes(toastBucketRel, AccessExclusiveLock);
bucketCloseRelation(toastBucketRel);
}
}
@ -3746,6 +3778,17 @@ static void heap_truncate_one_rel_for_bucket(Relation rel, Partition part)
void heap_truncate_one_rel(Relation rel)
{
Oid toastrelid;
LOCKMODE lockmode = AccessExclusiveLock;
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (!gtt_storage_attached(RelationGetRelid(rel)))
return;
/*
* Truncate global temp table only need RowExclusiveLock
*/
lockmode = RowExclusiveLock;
}
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(rel))) {
FdwRoutine* fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(rel));
@ -3766,12 +3809,12 @@ void heap_truncate_one_rel(Relation rel)
/* If the relation is a cloumn store */
if (RelationIsColStore(rel)) {
/* cudesc */
Relation cudesc_rel = heap_open(rel->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation cudesc_rel = heap_open(rel->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(cudesc_rel);
heap_close(cudesc_rel, NoLock);
/* delta */
Relation delta_rel = heap_open(rel->rd_rel->reldeltarelid, AccessExclusiveLock);
Relation delta_rel = heap_open(rel->rd_rel->reldeltarelid, lockmode);
heap_truncate_one_rel(delta_rel);
heap_close(delta_rel, NoLock);
@ -3782,16 +3825,16 @@ void heap_truncate_one_rel(Relation rel)
/* If there is a toast table, truncate that too */
toastrelid = rel->rd_rel->reltoastrelid;
if (OidIsValid(toastrelid)) {
Relation toastrel = heap_open(toastrelid, AccessExclusiveLock);
Relation toastrel = heap_open(toastrelid, lockmode);
RelationTruncate(toastrel, 0);
RelationTruncateIndexes(toastrel);
RelationTruncateIndexes(toastrel, lockmode);
/* keep the lock... */
heap_close(toastrel, NoLock);
}
}
/* If the relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rel);
RelationTruncateIndexes(rel, lockmode);
} else /* partitioned table */
{
List* partOidList = NIL;
@ -3805,7 +3848,7 @@ void heap_truncate_one_rel(Relation rel)
/* truncate each partition */
partOidList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_PARTITION, rel->rd_id);
foreach (partCell, partOidList) {
Partition p = partitionOpen(rel, HeapTupleGetOid((HeapTuple)lfirst(partCell)), AccessExclusiveLock);
Partition p = partitionOpen(rel, HeapTupleGetOid((HeapTuple)lfirst(partCell)), lockmode);
/*
* two levels and in dn
@ -3830,7 +3873,7 @@ void heap_truncate_one_rel(Relation rel)
ListCell* cell1 = NULL;
IndexInfo* indexInfo = NULL;
Oid indexId = lfirst_oid(indCell);
currentIndex = index_open(indexId, AccessExclusiveLock);
currentIndex = index_open(indexId, lockmode);
indexInfo = BuildIndexInfo(currentIndex);
@ -3838,7 +3881,7 @@ void heap_truncate_one_rel(Relation rel)
foreach (cell1, currentParttiionIndexList) {
Partition indexPart =
partitionOpen(currentIndex, HeapTupleGetOid((HeapTuple)lfirst(cell1)), AccessExclusiveLock);
partitionOpen(currentIndex, HeapTupleGetOid((HeapTuple)lfirst(cell1)), lockmode);
Partition p;
if (RELATION_OWN_BUCKET(currentIndex)) {
@ -3848,7 +3891,7 @@ void heap_truncate_one_rel(Relation rel)
}
/* truncate psort relation */
if (unlikely(currentIndex->rd_rel->relam == PSORT_AM_OID)) {
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, AccessExclusiveLock);
Relation psort_rel = heap_open(currentIndex->rd_rel->relcudescrelid, lockmode);
heap_truncate_one_rel(psort_rel);
heap_close(psort_rel, NoLock);
}
@ -3872,10 +3915,10 @@ void heap_truncate_one_rel(Relation rel)
Form_pg_partition partForm = (Form_pg_partition)GETSTRUCT(tup);
if (partForm->reltoastrelid != InvalidOid) {
Relation toastrel = heap_open(partForm->reltoastrelid, AccessExclusiveLock);
Relation toastrel = heap_open(partForm->reltoastrelid, lockmode);
RelationTruncate(toastrel, 0);
RelationTruncateIndexes(toastrel);
RelationTruncateIndexes(toastrel, lockmode);
/* keep the lock... */
heap_close(toastrel, NoLock);
}
@ -3884,6 +3927,11 @@ void heap_truncate_one_rel(Relation rel)
freePartList(partOidList);
}
// for GTT
if (RELATION_IS_GLOBAL_TEMP(rel)) {
up_gtt_relstats(rel, 0, 0, 0, u_sess->utils_cxt.RecentXmin);
}
}
/*
@ -4087,7 +4135,6 @@ int2vector* buildPartitionKey(List* keys, TupleDesc tupledsc)
columName = ((Value*)linitial(col->fields))->val.str;
finded = false;
for (j = 0; j < attnum; j++) {
if (strcmp(columName, attrs[j]->attname.data) == 0) {
partkey->values[i] = attrs[j]->attnum;
finded = true;
@ -4106,16 +4153,44 @@ int2vector* buildPartitionKey(List* keys, TupleDesc tupledsc)
return partkey;
}
/*
* @@GaussDB@@
* Target : data partition
* Brief :
* Description :
* Notes :
*/
static oidvector* buldIntervalTablespace(IntervalPartitionDefState* intervalPartDef)
static oidvector* BuildIntervalTablespace(const IntervalPartitionDefState* intervalPartDef)
{
return (oidvector*)NULL;
if (intervalPartDef->intervalTablespaces == NULL || intervalPartDef->intervalTablespaces->length == 0) {
return NULL;
}
oidvector* tablespaceVec = buildoidvector(NULL, intervalPartDef->intervalTablespaces->length);
ListCell* cell = NULL;
int i = 0;
const char* tablespaceName;
Oid tableSpaceOid;
AclResult aclresult;
foreach (cell, intervalPartDef->intervalTablespaces) {
tablespaceName = ((Value*)lfirst(cell))->val.str;
tableSpaceOid = get_tablespace_oid(tablespaceName, false);
if (tableSpaceOid != u_sess->proc_cxt.MyDatabaseTableSpace) {
aclresult = pg_tablespace_aclcheck(tableSpaceOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK) {
aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespaceName);
}
}
tablespaceVec->values[i] = tableSpaceOid;
i++;
}
return tablespaceVec;
}
static Datum BuildInterval(Node* partInterval)
{
Assert(IsA(partInterval, A_Const));
A_Const* constNode = (A_Const*)partInterval;
Assert(IsA(&constNode->val, String));
ArrayBuildState* astate = NULL;
astate = accumArrayResult(
astate, PointerGetDatum(cstring_to_text(constNode->val.val.str)), false, TEXTOID, CurrentMemoryContext);
return makeArrayResult(astate, CurrentMemoryContext);
}
/*
@ -4702,7 +4777,7 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO
}
}
/*create partition */
/* create partition */
if (!OidIsValid(partrelfileOid) && u_sess->proc_cxt.IsBinaryUpgrade
&& binary_upgrade_is_next_part_pg_partition_oid_valid()) {
newPartitionOid = binary_upgrade_get_next_part_pg_partition_oid();
@ -4710,7 +4785,7 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO
} else if (!OidIsValid(partrelfileOid)) {
newPartitionOid = GetNewRelFileNode(newPartitionTableSpaceOid,
pgPartRel,
RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table)*/
RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table) */
} else {
Assert(t_thrd.xact_cxt.inheritFileNode);
ereport(NOTICE,
@ -4742,14 +4817,14 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO
newPartition->pd_part->relcudescidx = InvalidOid;
newPartition->pd_part->indisusable = true;
/*step 3: insert into pg_partition tuple*/
/* step 3: insert into pg_partition tuple */
addNewPartitionTuple(pgPartRel, /* RelationData pointer for pg_partition */
newPartition, /* PartitionData pointer for partition */
NULL, /* */
NULL,
(Datum)0, /*interval*/
boundaryValue, /*max values */
(Datum)0, /*transition point*/
(Datum)0, /* interval*/
boundaryValue, /* max values */
(Datum)0, /* transition point */
reloptions);
relation = relation_open(partTableOid, NoLock);
@ -4760,6 +4835,362 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO
return newPartitionOid;
}
#define IsDigital(_ch) (((_ch) >= '0') && ((_ch) <= '9'))
static unsigned ExtractIntervalPartNameSuffix(const char* partName)
{
if (partName == NULL) {
return 0;
}
size_t len = strlen(partName);
size_t constPartLen = strlen(INTERVAL_PARTITION_NAME_PREFIX);
/* 5 is length of MAX_PARTITION_NUM */
if (len <= constPartLen || len > constPartLen + INTERVAL_PARTITION_NAME_SUFFIX_LEN) {
return 0;
}
if (strncmp(partName, INTERVAL_PARTITION_NAME_PREFIX, constPartLen) != 0) {
return 0;
}
for (size_t i = constPartLen; i < len; ++i) {
if (!IsDigital(partName[i])) {
return 0;
}
}
return (unsigned)atoi(partName + constPartLen);
}
int RangeElementOidCmp(const void* a, const void* b)
{
const RangeElement* rea = (const RangeElement*)a;
const RangeElement* reb = (const RangeElement*)b;
if (rea->partitionOid < reb->partitionOid) {
return 1;
}
if (rea->partitionOid == reb->partitionOid) {
return 0;
}
return -1;
}
char* GenIntervalPartitionName(Relation rel)
{
unsigned suffix = 0;
Oid existingPartOid;
RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap;
RangeElement* eles = CopyRangeElementsWithoutBoundary(partMap->rangeElements, partMap->rangeElementsNum);
/* sort desc by oid */
qsort(eles, partMap->rangeElementsNum, sizeof(RangeElement), RangeElementOidCmp);
for (int i = 0; i < partMap->rangeElementsNum; ++i) {
/* merge or split may result in range oid bigger than interval range oid */
if (!eles[i].isInterval) {
continue;
}
char* name = PartitionOidGetName(eles[i].partitionOid);
if ((suffix = ExtractIntervalPartNameSuffix(name)) != 0) {
pfree(name);
break;
}
}
pfree(eles);
char* partName = (char*)palloc0(NAMEDATALEN);
error_t rc;
while (true) {
++suffix;
suffix = (suffix % MAX_PARTITION_NUM == 0 ? MAX_PARTITION_NUM : suffix % MAX_PARTITION_NUM);
rc = snprintf_s(partName, NAMEDATALEN, NAMEDATALEN - 1, INTERVAL_PARTITION_NAME_PREFIX_FMT, suffix);
securec_check_ss(rc, "\0", "\0");
existingPartOid = partitionNameGetPartitionOid(
rel->rd_id, partName, PART_OBJ_TYPE_TABLE_PARTITION, AccessExclusiveLock, true, false, NULL, NULL, NoLock);
if (!OidIsValid(existingPartOid)) {
return partName;
}
}
}
Oid GetRecentUsedTablespace(Relation rel)
{
RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap;
Assert(partMap->rangeElementsNum >= 1);
RangeElement* maxOidEle = &partMap->rangeElements[0];
for (int i = 1; i < partMap->rangeElementsNum; ++i) {
if (partMap->rangeElements[i].partitionOid > maxOidEle->partitionOid) {
maxOidEle = &partMap->rangeElements[i];
}
}
/* no interval partition yet */
if (!maxOidEle->isInterval) {
return InvalidOid;
}
return PartitionOidGetTablespace(maxOidEle->partitionOid);
}
Oid ChooseIntervalTablespace(Relation rel)
{
const oidvector* tablespaceVec = ((RangePartitionMap*)rel->partMap)->intervalTablespace;
Assert(tablespaceVec->dim1 >= 1);
if (tablespaceVec->dim1 == 1) {
return tablespaceVec->values[0];
}
const Oid recentUsed = GetRecentUsedTablespace(rel);
if (!OidIsValid(recentUsed)) {
return tablespaceVec->values[0];
}
int i = 0;
for (; i < tablespaceVec->dim1; ++i) {
if (tablespaceVec->values[i] == recentUsed) {
break;
}
}
return tablespaceVec->values[(i + 1) % tablespaceVec->dim1];
}
Oid HeapAddIntervalPartition(Relation pgPartRel, Relation rel, Oid partTableOid, Oid partrelfileOid, Oid partTablespace,
Oid bucketOid, Datum boundaryValue, Oid ownerid, Datum reloptions)
{
Oid newPartitionOid = InvalidOid;
Oid newPartitionTableSpaceOid = InvalidOid;
Relation relation;
Partition newPartition;
if (((RangePartitionMap*)rel->partMap)->intervalTablespace != NULL) {
newPartitionTableSpaceOid = ChooseIntervalTablespace(rel);
}
if (!OidIsValid(newPartitionTableSpaceOid)) {
newPartitionTableSpaceOid = partTablespace;
}
/* Check permissions except when using database's default */
if (OidIsValid(newPartitionTableSpaceOid) && newPartitionTableSpaceOid != u_sess->proc_cxt.MyDatabaseTableSpace) {
AclResult aclresult = pg_tablespace_aclcheck(newPartitionTableSpaceOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK) {
aclcheck_error(aclresult, ACL_KIND_TABLESPACE, get_tablespace_name(newPartitionTableSpaceOid));
}
}
/* create partition */
if (!OidIsValid(partrelfileOid) && u_sess->proc_cxt.IsBinaryUpgrade &&
binary_upgrade_is_next_part_pg_partition_oid_valid()) {
newPartitionOid = binary_upgrade_get_next_part_pg_partition_oid();
partrelfileOid = binary_upgrade_get_next_part_pg_partition_rfoid();
} else if (!OidIsValid(partrelfileOid)) {
newPartitionOid = GetNewRelFileNode(newPartitionTableSpaceOid,
pgPartRel,
RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table) */
} else {
Assert(t_thrd.xact_cxt.inheritFileNode);
ereport(NOTICE, (errmsg("Define inheritFileNode %u for new interval partition", partrelfileOid)));
}
LockPartitionOid(partTableOid, (uint32)newPartitionOid, AccessExclusiveLock);
char* partName = GenIntervalPartitionName(rel);
newPartition = heapCreatePartition(partName, /* partition's name */
false, /* false for partition */
newPartitionTableSpaceOid, /* partition's tablespace */
newPartitionOid, /* partition's oid */
partrelfileOid,
bucketOid,
ownerid);
pfree(partName);
Assert(newPartitionOid == PartitionGetPartid(newPartition));
newPartition->pd_part->parttype = PART_OBJ_TYPE_TABLE_PARTITION;
newPartition->pd_part->parentid = partTableOid;
newPartition->pd_part->rangenum = 0;
newPartition->pd_part->intervalnum = 0;
newPartition->pd_part->partstrategy = PART_STRATEGY_INTERVAL;
newPartition->pd_part->reltoastrelid = InvalidOid;
newPartition->pd_part->reltoastidxid = InvalidOid;
newPartition->pd_part->indextblid = InvalidOid;
newPartition->pd_part->reldeltarelid = InvalidOid;
newPartition->pd_part->reldeltaidx = InvalidOid;
newPartition->pd_part->relcudescrelid = InvalidOid;
newPartition->pd_part->relcudescidx = InvalidOid;
newPartition->pd_part->indisusable = true;
/* step 3: insert into pg_partition tuple*/
addNewPartitionTuple(pgPartRel, /* RelationData pointer for pg_partition */
newPartition, /* PartitionData pointer for partition */
NULL,
NULL,
(Datum)0, /* interval */
boundaryValue, /* max values */
(Datum)0, /* transition point */
reloptions);
relation = relation_open(partTableOid, NoLock);
PartitionCloseSmgr(newPartition);
partitionClose(relation, newPartition, NoLock);
relation_close(relation, NoLock);
return newPartitionOid;
}
Timestamp Align2UpBoundary(Timestamp value, Interval* intervalValue, Timestamp boundary)
{
Timestamp nearbyBoundary = boundary;
Interval* diff = DatumGetIntervalP(timestamp_mi(value, boundary));
/* approximate multiple */
int multiple = (int)(INTERVAL_TO_USEC(diff) / INTERVAL_TO_USEC(intervalValue));
pfree(diff);
if (multiple != 0) {
Interval* integerInterval = DatumGetIntervalP(interval_mul(intervalValue, (float8)multiple));
nearbyBoundary = DatumGetTimestamp(timestamp_pl_interval(boundary, integerInterval));
pfree(integerInterval);
}
if (nearbyBoundary <= value) {
while (true) {
nearbyBoundary = DatumGetTimestamp(timestamp_pl_interval(nearbyBoundary, intervalValue));
if (nearbyBoundary > value) {
return nearbyBoundary;
}
}
} else {
while (true) {
Timestamp res = DatumGetTimestamp(timestamp_mi_interval(nearbyBoundary, intervalValue));
if (res <= value) {
return nearbyBoundary;
}
nearbyBoundary = res;
}
}
}
Datum Timestamp2Boundarys(Relation rel, Timestamp ts)
{
Const consts;
RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap;
bool isTimestamptz = partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPTZOID;
Datum columnRaw = TimestampGetDatum(ts);
int2vector* partKeyColumn = partMap->partitionKey;
Assert(partKeyColumn->dim1 == 1);
(void)transformDatum2Const(rel->rd_att, partKeyColumn->values[0], columnRaw, false, &consts);
List* bondary = list_make1(&consts);
Datum res = transformPartitionBoundary(bondary, &isTimestamptz);
list_free(bondary);
return res;
}
Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
{
RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap;
int2vector* partKeyColumn = partMap->partitionKey;
Assert(partKeyColumn->dim1 == 1);
Assert(partMap->type.type == PART_TYPE_INTERVAL);
Assert(partMap->rangeElementsNum >= 1);
Assert(partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPOID ||
partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPTZOID);
bool isNull = false;
Datum columnRaw = fastgetattr(tuple, partKeyColumn->values[0], rel->rd_att, &isNull);
Timestamp value = DatumGetTimestamp(columnRaw);
Timestamp boundaryTs =
DatumGetTimestamp(partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->constvalue);
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
}
Oid AddNewIntervalPartition(Relation rel, HeapTuple insertTuple)
{
Relation pgPartRel = NULL;
Oid newPartOid = InvalidOid;
Datum newRelOptions;
Datum relOptions;
HeapTuple tuple;
bool isNull = false;
List* oldRelOptions = NIL;
Oid bucketOid;
if (rel->partMap->isDirty) {
CacheInvalidateRelcache(rel);
}
/* it will accept invalidation messages generated by other sessions in lockRelationForAddIntervalPartition. */
lockRelationForAddIntervalPartition(rel);
partitionRoutingForTuple(rel, insertTuple, u_sess->catalog_cxt.route);
/* if the partition exists, return partition's oid */
if (u_sess->catalog_cxt.route->fileExist) {
Assert(OidIsValid(u_sess->catalog_cxt.route->partitionId));
unLockRelationForAddIntervalPartition(rel);
return u_sess->catalog_cxt.route->partitionId;
}
/* can not add more partition, because more enough */
if ((getNumberOfPartitions(rel) + 1) > MAX_PARTITION_NUM) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("too many partitions for partitioned table"),
errhint("Number of partitions can not be more than %d", MAX_PARTITION_NUM)));
}
/* whether has the unusable local index */
if (!checkRelationLocalIndexesUsable(rel)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("can't add partition bacause the relation %s has unusable local index",
NameStr(rel->rd_rel->relname)),
errhint("please reindex the unusable index first.")));
}
pgPartRel = relation_open(PartitionRelationId, RowExclusiveLock);
/* add new partition entry in pg_partition */
/* TRANSFORM into target first */
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(rel->rd_id));
relOptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isNull);
oldRelOptions = untransformRelOptions(relOptions);
newRelOptions = transformRelOptions((Datum)0, oldRelOptions, NULL, NULL, false, false);
ReleaseSysCache(tuple);
if (oldRelOptions != NIL) {
list_free_ext(oldRelOptions);
}
bucketOid = RelationGetBucketOid(rel);
newPartOid = HeapAddIntervalPartition(pgPartRel,
rel,
rel->rd_id,
InvalidOid,
rel->rd_rel->reltablespace,
bucketOid,
GetPartBoundaryByTuple(rel, insertTuple),
rel->rd_rel->relowner,
(Datum)newRelOptions);
CommandCounterIncrement();
addIndexForPartition(rel, newPartOid);
addToastTableForNewPartition(rel, newPartOid);
/* invalidate relation */
CacheInvalidateRelcache(rel);
/* close relation, done */
relation_close(pgPartRel, NoLock);
/*
* We must bump the command counter to make the newly-created
* table partition visible for using.
*/
CommandCounterIncrement();
return newPartOid;
}
static void addNewPartitionTupleForValuePartitionedTable(Relation pg_partition_rel, const char* relname,
const Oid reloid, const Oid reltablespaceid, const TupleDesc reltupledesc, const PartitionState* partTableState,
Datum reloptions)
@ -4872,10 +5303,10 @@ static void addNewPartitionTupleForTable(Relation pg_partition_rel, const char*
}
partition_key_attr_no = buildPartitionKey(partTableState->partitionKey, reltupledesc);
interval_talespace = buldIntervalTablespace(partTableState->intervalPartDef);
interval = (Datum)0;
transition_point = (Datum)0;
if (partTableState->intervalPartDef != NULL) {
interval_talespace = BuildIntervalTablespace(partTableState->intervalPartDef);
interval = BuildInterval(partTableState->intervalPartDef->partInterval);
}
/*step1: create partition relation, initialize and set tuple properties*/
if (u_sess->proc_cxt.IsBinaryUpgrade && OidIsValid(u_sess->upg_cxt.binary_upgrade_next_partrel_pg_partition_oid)) {
@ -4930,6 +5361,10 @@ static void addNewPartitionTupleForTable(Relation pg_partition_rel, const char*
if (interval_talespace != NULL) {
pfree(interval_talespace);
}
if (interval != 0) {
pfree(DatumGetPointer(interval));
}
}
/*
@ -5160,6 +5595,9 @@ Oid heapTupleGetPartitionId(Relation rel, HeapTuple tuple)
ereport(ERROR,
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
} break;
case PART_AREA_INTERVAL: {
return AddNewIntervalPartition(rel, tuple);
} break;
/* never happen; just to be self-contained */
default: {
ereport(ERROR,
@ -5302,18 +5740,6 @@ static Oid binary_upgrade_get_next_part_toast_pg_class_rfoid()
return old_part_toast_pg_class_rfoid;
}
/*
* @@GaussDB@@
* Target : data partition
* Brief : create a interval partition.
* Description :
* Notes :
*/
Oid createNewIntervalFile(Relation rel, int seqNum)
{
return InvalidOid;
}
static int TransformClusterColNameList(Oid relId, List* colList, int16* attnums)
{
ListCell* l = NULL;

View File

@ -21,6 +21,7 @@
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
@ -43,6 +44,7 @@
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/vacuum.h"
@ -689,6 +691,11 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
int i;
char relpersistence;
Oid psortRelationId = InvalidOid;
bool skip_create_storage = false;
if (RELATION_IS_GLOBAL_TEMP(heapRelation) && !gtt_storage_attached(RelationGetRelid(heapRelation))) {
skip_create_storage = true;
}
is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
@ -766,6 +773,20 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
if (get_relname_relid(indexRelationName, namespaceId))
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists", indexRelationName)));
if (RELATION_IS_GLOBAL_TEMP(heapRelation))
{
/* No support create index on global temp table use concurrent mode yet */
if (concurrent)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot reindex global temporary tables concurrently")));
/* if global temp table not init storage, then skip build index */
if (!gtt_storage_attached(RelationGetRelid(heapRelation))) {
skip_build = true;
}
}
/*
* construct tuple descriptor for index tuples
@ -828,7 +849,8 @@ Oid index_create(Relation heapRelation, const char* indexRelationName, Oid index
mapped_relation,
allow_system_table_mods,
REL_CMPRS_NOT_SUPPORT,
heapRelation->rd_rel->relowner);
heapRelation->rd_rel->relowner,
skip_create_storage);
Assert(indexRelationId == RelationGetRelid(indexRelation));
@ -1413,6 +1435,15 @@ void index_drop(Oid indexId, bool concurrent)
VirtualTransactionId* old_lockholders = NULL;
List* partIndexlist = NIL;
/*
* A temporary relation uses a non-concurrent DROP. Other backends can't
* access a temporary relation, so there's no harm in grabbing a stronger
* lock (see comments in RemoveRelations), and a non-concurrent DROP is
* more efficient.
*/
Assert(!(get_rel_persistence(indexId) == RELPERSISTENCE_TEMP ||
get_rel_persistence(indexId) == RELPERSISTENCE_GLOBAL_TEMP) ||
(!concurrent));
/*
* To drop an index safely, we must grab exclusive lock on its parent
@ -1443,6 +1474,14 @@ void index_drop(Oid indexId, bool concurrent)
*/
CheckTableNotInUse(userIndexRelation, "DROP INDEX");
/* We allow to drop index on global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(userHeapRelation)) {
if (is_other_backend_use_gtt(RelationGetRelid(userHeapRelation))) {
elog(ERROR,
"can not drop index %s when other backend attached this global temp table.",
RelationGetRelationName(userHeapRelation));
}
}
/*
* Drop Index Concurrently is more or less the reverse process of Create
* Index Concurrently.
@ -1760,36 +1799,69 @@ IndexInfo* BuildIndexInfo(Relation index)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid indnatts %d for index %u", numKeys, RelationGetRelid(index))));
ii->ii_NumIndexAttrs = numKeys;
for (i = 0; i < numKeys; i++)
ii = makeIndexInfo(indexStruct->indnatts,
RelationGetIndexExpressions(index),
RelationGetIndexPredicate(index),
indexStruct->indisunique,
IndexIsReady(indexStruct),
false);
/* fill in attribute numbers */
for (i = 0; i < numKeys; i++) {
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
/* fetch any expressions needed for expressional indexes */
ii->ii_Expressions = RelationGetIndexExpressions(index);
ii->ii_ExpressionsState = NIL;
/* fetch index predicate if any */
ii->ii_Predicate = RelationGetIndexPredicate(index);
ii->ii_PredicateState = NIL;
}
/* fetch exclusion constraint info if any */
if (indexStruct->indisexclusion) {
RelationGetExclusionInfo(index, &ii->ii_ExclusionOps, &ii->ii_ExclusionProcs, &ii->ii_ExclusionStrats);
} else {
ii->ii_ExclusionOps = NULL;
ii->ii_ExclusionProcs = NULL;
ii->ii_ExclusionStrats = NULL;
}
return ii;
}
/* ----------------
* BuildDummyIndexInfo
* Construct a dummy IndexInfo record for an open index
*
* This differs from the real BuildIndexInfo in that it will never run any
* user-defined code that might exist in index expressions or predicates.
* Instead of the real index expressions, we return null constants that have
* the right types/typmods/collations. Predicates and exclusion clauses are
* just ignored. This is sufficient for the purpose of truncating an index,
* since we will not need to actually evaluate the expressions or predicates;
* the only thing that's likely to be done with the data is construction of
* a tupdesc describing the index's rowtype.
* ----------------
*/
IndexInfo* BuildDummyIndexInfo(Relation index)
{
IndexInfo* ii;
Form_pg_index indexStruct = index->rd_index;
int i;
int numAtts;
/* check the number of keys, and copy attr numbers into the IndexInfo */
numAtts = indexStruct->indnatts;
if (numAtts < 1 || numAtts > INDEX_MAX_KEYS) {
elog(ERROR, "invalid indnatts %d for index %u", numAtts, RelationGetRelid(index));
}
/* other info */
ii->ii_Unique = indexStruct->indisunique;
ii->ii_ReadyForInserts = IndexIsReady(indexStruct);
/*
* Create the node, using dummy index expressions, and pretending there is
* no predicate.
*/
ii = makeIndexInfo(indexStruct->indnatts,
RelationGetDummyIndexExpressions(index),
NIL,
indexStruct->indisunique,
indexStruct->indisready,
false);
/* initialize index-build state to default */
ii->ii_Concurrent = false;
ii->ii_BrokenHotChain = false;
ii->ii_PgClassAttrId = 0;
/* fill in attribute numbers */
for (i = 0; i < numAtts; i++) {
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
}
/* We ignore the exclusion constraint if any */
return ii;
}
@ -1889,7 +1961,12 @@ void index_update_stats(
HeapTuple tuple;
Form_pg_class rd_rel;
bool dirty = false;
bool is_gtt = false;
/* update index stats into localhash and rel_rd_rel for global temp table */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
is_gtt = true;
}
/*
* We always update the pg_class row using a non-transactional,
* overwrite-in-place update. There are several reasons for this:
@ -1996,18 +2073,30 @@ void index_update_stats(
else /* don't bother for indexes */
relallvisible = 0;
if (rd_rel->relpages != (float8)relpages) {
if (is_gtt) {
rel->rd_rel->relpages = static_cast<int32>(relpages);
} else if (rd_rel->relpages != (float8)relpages) {
rd_rel->relpages = (float8)relpages;
dirty = true;
}
if (rd_rel->reltuples != (float8)reltuples) {
if (is_gtt) {
rel->rd_rel->reltuples = (float4) reltuples;
} else if (rd_rel->reltuples != (float8)reltuples) {
rd_rel->reltuples = (float8)reltuples;
dirty = true;
}
if (rd_rel->relallvisible != (int32)relallvisible) {
if (is_gtt) {
rel->rd_rel->relallvisible = (int32) relallvisible;
} else if (rd_rel->relallvisible != (int32)relallvisible) {
rd_rel->relallvisible = (int32)relallvisible;
dirty = true;
}
if (is_gtt) {
up_gtt_relstats(rel, relpages, reltuples, relallvisible, InvalidTransactionId);
}
}
#ifdef PGXC
}
@ -2311,12 +2400,25 @@ void index_build(Relation heapRelation, Partition heapPartition, Relation indexR
relation_close(psortRel, NoLock);
}
if (RELATION_IS_GLOBAL_TEMP(indexRelation)) {
if (indexRelation->rd_smgr == NULL) {
/* Open it at the smgr level if not already done */
RelationOpenSmgr(indexRelation);
}
if (!gtt_storage_attached(RelationGetRelid(indexRelation)) ||
!smgrexists(indexRelation->rd_smgr, MAIN_FORKNUM)) {
gtt_force_enable_index(indexRelation);
RelationCreateStorage(indexRelation->rd_node, RELPERSISTENCE_GLOBAL_TEMP, indexRelation->rd_rel->relowner,
indexRelation->rd_bucketoid, indexRelation);
}
}
/*
* Call the access method's build procedure
*/
hasbucket = (!isPartition && RELATION_CREATE_BUCKET(heapRelation)) ||
(isPartition && RELATION_OWN_BUCKETKEY(heapRelation));
if (hasbucket == true) {
if (hasbucket) {
index_build_storage_for_bucket(heapRelation,
indexRelation,
heapPartition,
@ -3527,7 +3629,8 @@ void reindex_indexpart_internal(Relation heapRelation, Relation iRel, IndexInfo*
/*
* reindex_index - This routine is used to recreate a single index
*/
void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks, AdaptMem* mem_info, bool db_wide)
void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks,
AdaptMem *memInfo, bool dbWide, char persistence)
{
Relation iRel, heapRelation;
Oid heapId;
@ -3615,19 +3718,19 @@ void reindex_index(Oid indexId, Oid indexPartId, bool skip_constraint_checks, Ad
/* workload client manager */
if (IS_PGXC_COORDINATOR && ENABLE_WORKLOAD_CONTROL) {
/* if operatorMem is already set, the mem check is already done */
if (mem_info != NULL && mem_info->work_mem == 0) {
if (memInfo != NULL && memInfo->work_mem == 0) {
EstIdxMemInfo(heapRelation, NULL, &indexInfo->ii_desc, indexInfo, iRel->rd_am->amname.data);
if (db_wide) {
if (dbWide) {
indexInfo->ii_desc.cost = g_instance.cost_cxt.disable_cost;
indexInfo->ii_desc.query_mem[0] = Max(STATEMENT_MIN_MEM * 1024, indexInfo->ii_desc.query_mem[0]);
}
WLMInitQueryPlan((QueryDesc*)&indexInfo->ii_desc, false);
dywlm_client_manager((QueryDesc*)&indexInfo->ii_desc, false);
AdjustIdxMemInfo(mem_info, &indexInfo->ii_desc);
AdjustIdxMemInfo(memInfo, &indexInfo->ii_desc);
}
} else if (IS_PGXC_DATANODE && mem_info != NULL && mem_info->work_mem > 0) {
indexInfo->ii_desc.query_mem[0] = mem_info->work_mem;
indexInfo->ii_desc.query_mem[1] = mem_info->max_mem;
} else if (IS_PGXC_DATANODE && memInfo != NULL && memInfo->work_mem > 0) {
indexInfo->ii_desc.query_mem[0] = memInfo->work_mem;
indexInfo->ii_desc.query_mem[1] = memInfo->max_mem;
}
if (!RELATION_IS_PARTITIONED(heapRelation)) /* for non partitioned table */
@ -3862,8 +3965,9 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
Oid indexOid = lfirst_oid(indexId);
Relation indexRel = index_open(indexOid, AccessShareLock);
if (is_pg_class)
if (is_pg_class) {
RelationSetIndexList(rel, doneIndexes, InvalidOid);
}
if ((((uint32)reindexType) & REINDEX_ALL_INDEX) ||
((((uint32)reindexType) & REINDEX_BTREE_INDEX) && (indexRel->rd_rel->relam == BTREE_AM_OID)) ||
@ -3873,17 +3977,19 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
((((uint32)reindexType) & REINDEX_GIST_INDEX) && (indexRel->rd_rel->relam == GIST_AM_OID))) {
index_close(indexRel, AccessShareLock);
reindex_index(
indexOid, InvalidOid, !(((uint32)flags) & REINDEX_REL_CHECK_CONSTRAINTS), memInfo, dbWide);
indexOid, InvalidOid, !((static_cast<uint32>(flags)) & REINDEX_REL_CHECK_CONSTRAINTS), memInfo,
dbWide, rel->rd_rel->relpersistence);
CommandCounterIncrement();
} else
} else {
index_close(indexRel, AccessShareLock);
}
/* Index should no longer be in the pending list */
Assert(!ReindexIsProcessingIndex(indexOid));
if (is_pg_class)
if (is_pg_class) {
doneIndexes = lappend_oid(doneIndexes, indexOid);
}
}
}
PG_CATCH();
@ -3895,8 +4001,9 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
PG_END_TRY();
ResetReindexPending();
if (is_pg_class)
if (is_pg_class) {
RelationSetIndexList(rel, indexIds, ClassOidIndexId);
}
/*
* Close rel, but continue to hold the lock.
@ -3904,8 +4011,7 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
heap_close(rel, NoLock);
// reset all local indexes on partition usable if needed
if (RELATION_IS_PARTITIONED(rel)) /* for partitioned table */
{
if (RELATION_IS_PARTITIONED(rel)) { /* for partitioned table */
Oid partOid;
ListCell* cell = NULL;
List* partOidList = relationGetPartitionOidList(rel);
@ -3918,16 +4024,14 @@ bool reindex_relation(Oid relid, int flags, int reindexType, AdaptMem* memInfo,
result = (indexIds != NIL);
if (!isPartitioned) /* for non partitioned table */
{
if (!isPartitioned) { /* for non partitioned table */
/*
* If the relation has a secondary toast rel, reindex that too while we
* still hold the lock on the master table.
*/
if ((((uint32)flags) & REINDEX_REL_PROCESS_TOAST) && OidIsValid(toast_relid))
result = reindex_relation(toast_relid, flags, REINDEX_BTREE_INDEX) || result;
} else /* for partitioned table */
{
} else { /* for partitioned table */
List* partTupleList = NULL;
ListCell* partCell = NULL;

View File

@ -593,6 +593,12 @@ void RangeVarAdjustRelationPersistence(RangeVar* newRelation, Oid nspid)
errmsg("cannot create temporary relation in non-temporary schema")));
}
break;
case RELPERSISTENCE_GLOBAL_TEMP: /* global temp table */
if (isAnyTempNamespace(nspid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot create global temp relations in temporary schemas")));
break;
case RELPERSISTENCE_PERMANENT:
if (isTempOrToastNamespace(nspid))
newRelation->relpersistence = RELPERSISTENCE_TEMP;

View File

@ -299,8 +299,7 @@ void AggregateCreate(const char* aggName, Oid aggNamespace, Oid* aggArgTypes, in
InvalidOid, /* no validator */
"aggregate_dummy", /* placeholder proc */
NULL, /* probin */
true, /* isAgg */
false, /* isWindowFunc */
PROKIND_AGGREGATE, /* prokind */
false, /* security invoker (currently not
* definable for agg) */
false, /* isLeakProof */

13
src/common/backend/catalog/pg_partition.cpp Executable file → Normal file
View File

@ -41,7 +41,8 @@
#include "utils/snapmgr.h"
void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, Oid new_part_id, int2vector* pkey,
oidvector* intablespace, Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions, char parttype)
const oidvector* tablespaces, Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions,
char parttype)
{
Datum values[Natts_pg_partition];
bool nulls[Natts_pg_partition];
@ -88,7 +89,13 @@ void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, O
nulls[Anum_pg_partition_partkey - 1] = true;
}
nulls[Anum_pg_partition_intablespace - 1] = true;
/* interval tablespaces */
if (tablespaces != NULL) {
values[Anum_pg_partition_intablespace - 1] = PointerGetDatum(tablespaces);
} else {
nulls[Anum_pg_partition_intablespace - 1] = true;
}
nulls[Anum_pg_partition_intspnum - 1] = true;
/* interval */
@ -586,7 +593,7 @@ static Oid getPartitionIndexFormData(Oid indexid, Oid partitionid, Form_pg_parti
heap_close(pg_partition, AccessShareLock);
/* If drop index occur before this function and after pg_get_indexdef_partitions, */
/* the index has been deleted now. Ext. If drop patition occur, the partition might be deleted.
/* the index has been deleted now. Ext. If drop patition occur, the partition might be deleted.
* Drop partition just use RowExclusiveLock for parellel performance. */
if (!found) {
ereport(ERROR,

View File

@ -106,7 +106,7 @@ static char* getCFunProbin(const char* probin, const char* fun_name, Oid procNam
static void checkFunctionConflicts(HeapTuple oldtup, const char* procedureName, Oid proowner, Oid returnType,
Datum allParameterTypes, Datum parameterModes, Datum parameterNames, bool returnsSet, bool replace, bool isOraStyle,
bool isAgg, bool isWindowFunc);
char prokind);
static bool user_define_func_check(Oid languageId, const char* probin, char** absolutePath, CFunType* function_type);
static const char* get_file_name(const char* filePath, CFunType function_type);
@ -677,12 +677,11 @@ static bool checkPackageFunctionConflicts(
* @in returnsSet: Return type if is set.
* @in replace: Is replace.
* @in isOraStyle: Is a style.
* @in isAgg: Is agg function.
* @in isWindowFunc: Is windows function.
* @in prokind: Procedure kind.
*/
static void checkFunctionConflicts(HeapTuple oldtup, const char* procedureName, Oid proowner, Oid returnType,
Datum allParameterTypes, Datum parameterModes, Datum parameterNames, bool returnsSet, bool replace, bool isOraStyle,
bool isAgg, bool isWindowFunc)
char prokind)
{
Datum proargnames;
bool isnull = false;
@ -778,8 +777,8 @@ static void checkFunctionConflicts(HeapTuple oldtup, const char* procedureName,
}
/* Can't change aggregate or window-function status, either */
if (oldproc->proisagg != isAgg) {
if (oldproc->proisagg) {
if ((PROC_IS_AGG(oldproc->prokind) || PROC_IS_AGG(prokind)) && oldproc->prokind != prokind) {
if (PROC_IS_AGG(oldproc->prokind)) {
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("function \"%s\" is an aggregate function", procedureName)));
@ -790,8 +789,8 @@ static void checkFunctionConflicts(HeapTuple oldtup, const char* procedureName,
}
}
if (oldproc->proiswindow != isWindowFunc) {
if (oldproc->proiswindow) {
if ((PROC_IS_WIN(oldproc->prokind) || PROC_IS_WIN(prokind)) && oldproc->prokind != prokind) {
if (PROC_IS_WIN(oldproc->prokind)) {
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function \"%s\" is a window function", procedureName)));
} else {
@ -897,7 +896,7 @@ static bool user_define_func_check(Oid languageId, const char* probin, char** ab
*/
Oid ProcedureCreate(const char* procedureName, Oid procNamespace, bool isOraStyle, bool replace, bool returnsSet,
Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char* prosrc, const char* probin,
bool isAgg, bool isWindowFunc, bool security_definer, bool isLeakProof, bool isStrict, char volatility,
char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility,
oidvector* parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames,
List* parameterDefaults, Datum proconfig, float4 procost, float4 prorows, int2vector* prodefaultargpos, bool fenced,
bool shippable, bool package)
@ -1145,8 +1144,7 @@ Oid ProcedureCreate(const char* procedureName, Oid procNamespace, bool isOraStyl
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc);
values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
@ -1244,8 +1242,7 @@ Oid ProcedureCreate(const char* procedureName, Oid procNamespace, bool isOraStyl
returnsSet,
replace,
isOraStyle,
isAgg,
isWindowFunc);
prokind);
bool isNull = false;
Datum ispackage = SysCacheGetAttr(PROCOID, oldtup, Anum_pg_proc_package, &isNull);

View File

@ -31,6 +31,7 @@
#include "catalog/catalog.h"
#include "catalog/dfsstore_ctlg.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "catalog/storage_xlog.h"
#include "catalog/pg_hashbucket_fn.h"
#include "commands/tablespace.h"
@ -38,6 +39,7 @@
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "threadpool/threadpool.h"
#include "utils/fmgroids.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@ -67,6 +69,7 @@ typedef struct PendingRelDelete {
RelFileNode relnode; /* relation that may need to be deleted */
ForkNumber forknum; /* MAIN_FORKNUM for row table; or valid column ForkNum */
BackendId backend; /* InvalidBackendId if not a temp rel */
Oid relOid; /* InvalidOid if not a global temp rel */
Oid ownerid; /* owner id for user space statistics */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
@ -117,6 +120,10 @@ static void StorageSetBackendAndLogged(_in_ char relpersistence, _out_ BackendId
*needs_wal = false;
}
break;
case RELPERSISTENCE_GLOBAL_TEMP:
*backend = BackendIdForTempRelations;
*needs_wal = false;
break;
case RELPERSISTENCE_UNLOGGED:
*backend = InvalidBackendId;
*needs_wal = false;
@ -136,8 +143,8 @@ static void StorageSetBackendAndLogged(_in_ char relpersistence, _out_ BackendId
* if it's a row-storage table, *whichAttr* must is *AllTheAttrs*.
* if it's a column-storage table, *whichAttr* >= *AllTheAttrs*.
*/
static void InsertStorageIntoPendingList(_in_ RelFileNode* rnode, _in_ AttrNumber attrnum, _in_ BackendId backend,
_in_ Oid ownerid, _in_ bool atCommit, _in_ bool isDfsTruncate = false)
static void InsertStorageIntoPendingList(_in_ const RelFileNode* rnode, _in_ AttrNumber attrnum, _in_ BackendId backend,
_in_ Oid ownerid, _in_ bool atCommit, _in_ bool isDfsTruncate = false, Relation rel = NULL)
{
PendingRelDelete* pending = (PendingRelDelete*)MemoryContextAlloc(u_sess->top_mem_cxt, sizeof(PendingRelDelete));
pending->relnode = *rnode;
@ -165,17 +172,22 @@ static void InsertStorageIntoPendingList(_in_ RelFileNode* rnode, _in_ AttrNumbe
}
}
pending->backend = backend;
pending->relOid = InvalidOid;
pending->ownerid = ownerid;
pending->atCommit = atCommit; /* false: delete if abort; true: delete if commit */
pending->nestLevel = GetCurrentTransactionNestLevel();
pending->next = u_sess->catalog_cxt.pendingDeletes;
u_sess->catalog_cxt.pendingDeletes = pending;
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(*rnode, AccessExclusiveLock);
if (RELATION_IS_GLOBAL_TEMP(rel)) {
pending->relOid = RelationGetRelid(rel);
} else {
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(*rnode, AccessExclusiveLock);
}
}
void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid ownerid)
static void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid ownerid, Relation rel = NULL)
{
SMgrRelation srel;
BackendId backend;
@ -190,7 +202,12 @@ void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid o
log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
/* Add the relation to the list of stuff to delete at abort */
InsertStorageIntoPendingList(&rnode, InvalidAttrNumber, backend, ownerid, false);
InsertStorageIntoPendingList(&rnode, InvalidAttrNumber, backend, ownerid, false, false, rel);
/* remember global temp table storage info to localhash */
if (rel && relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
remember_gtt_storage_info(rnode, rel);
}
}
/*
@ -204,12 +221,12 @@ void RelationCreateStorageInternal(RelFileNode rnode, char relpersistence, Oid o
* This function is transactional. The creation is WAL-logged, and if the
* transaction aborts later on, the storage will be destroyed.
*/
void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid)
void RelationCreateStorage(RelFileNode rnode, char relpersistence, Oid ownerid, Oid bucketOid, Relation rel)
{
if (OidIsValid(bucketOid) && (bucketOid != VirtualBktOid)) {
BucketCreateStorage(rnode, bucketOid, ownerid);
} else {
RelationCreateStorageInternal(rnode, relpersistence, ownerid);
RelationCreateStorageInternal(rnode, relpersistence, ownerid, rel);
}
}
@ -328,6 +345,17 @@ void CStoreRelDropColumn(Relation rel, AttrNumber attrnum, Oid ownerid)
*/
void RelationDropStorage(Relation rel, bool isDfsTruncate)
{
// global temp table files may not exist
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (rel->rd_smgr == NULL) {
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
}
if (!smgrexists(rel->rd_smgr, MAIN_FORKNUM)) {
return;
}
}
/*
* First we must push the column file, column bcm file to the pendingDeletes and
* then push the logical table file to pendingDeletes.
@ -369,7 +397,7 @@ void RelationDropStorage(Relation rel, bool isDfsTruncate)
} else {
/* Add the relation to the list of stuff to delete at commit */
InsertStorageIntoPendingList(
&rel->rd_node, InvalidAttrNumber, rel->rd_backend, rel->rd_rel->relowner, true, isDfsTruncate);
&rel->rd_node, InvalidAttrNumber, rel->rd_backend, rel->rd_rel->relowner, true, isDfsTruncate, rel);
}
/*
@ -536,6 +564,11 @@ void RelationTruncate(Relation rel, BlockNumber nblocks)
if (bcm)
BCM_truncate(rel);
/* skip truncating if global temp table index does not exist */
if (RELATION_IS_GLOBAL_TEMP(rel) && !smgrexists(rel->rd_smgr, MAIN_FORKNUM)) {
return;
}
/*
* We WAL-log the truncation before actually truncating, which means
* trouble if the truncation fails. If we then crash, the WAL replay
@ -570,9 +603,10 @@ void RelationTruncate(Relation rel, BlockNumber nblocks)
if (fsm || vm)
XLogFlush(lsn);
}
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(rel->rd_node, AccessExclusiveLock);
if (!RELATION_IS_GLOBAL_TEMP(rel)) {
/* Lock RelFileNode to control concurrent with Catchup Thread */
LockRelFileNode(rel->rd_node, AccessExclusiveLock);
}
/* Do the real work */
smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks);
@ -686,7 +720,8 @@ void smgrDoPendingDeletes(bool isCommit)
/* do deletion if called for */
if (pending->atCommit == isCommit) {
if (!IsValidColForkNum(pending->forknum)) {
RowRelationDoDeleteFiles(pending->relnode, pending->backend, pending->ownerid);
RowRelationDoDeleteFiles(
pending->relnode, pending->backend, pending->ownerid, pending->relOid, isCommit);
/*
* "CREATE/DROP hdfs table" will use Two-Phrases Commit Transaction,
@ -1900,7 +1935,7 @@ void ColumnRelationDoDeleteFiles(RelFileNode* rnode, ForkNumber forknum, Backend
}
/* Delete all the physical files for row relation. */
void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid)
void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid, Oid relOid, bool isCommit)
{
/* decrease the permanent space on users' record */
uint64 size = GetSMgrRelSize(&rnode, backend, InvalidForkNumber);
@ -1912,6 +1947,11 @@ void RowRelationDoDeleteFiles(RelFileNode rnode, BackendId backend, Oid ownerid)
smgrdounlink(srel, false);
smgrclose(srel);
/* clean global temp table flags when transaction commit or rollback */
if (SmgrIsTemp(srel) && relOid != InvalidOid && gtt_storage_attached(relOid)) {
forget_gtt_storage_info(relOid, rnode, isCommit);
}
/*
* After files are deleted, append this filenode into BCM file list,
* so that we know all the BCM shared buffers of column relation has been

File diff suppressed because it is too large Load Diff

View File

@ -182,6 +182,117 @@ CREATE VIEW pg_indexes AS
LEFT JOIN pg_tablespace T ON (T.oid = I.reltablespace)
WHERE C.relkind = 'r' AND I.relkind = 'i';
-- For global temporary table
CREATE VIEW pg_gtt_relstats WITH (security_barrier) AS
SELECT n.nspname AS schemaname,
c.relname AS tablename,
(select relfilenode from pg_get_gtt_relstats(c.oid)),
(select relpages from pg_get_gtt_relstats(c.oid)),
(select reltuples from pg_get_gtt_relstats(c.oid)),
(select relallvisible from pg_get_gtt_relstats(c.oid)),
(select relfrozenxid from pg_get_gtt_relstats(c.oid)),
(select relminmxid from pg_get_gtt_relstats(c.oid))
FROM
pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','p','i','t');
CREATE VIEW pg_gtt_attached_pids WITH (security_barrier) AS
SELECT n.nspname AS schemaname,
c.relname AS tablename,
c.oid AS relid,
array(select pid from pg_gtt_attached_pid(c.oid)) AS pids
FROM
pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','S');
CREATE VIEW pg_gtt_stats WITH (security_barrier) AS
SELECT s.nspname AS schemaname,
s.relname AS tablename,
s.attname,
s.stainherit AS inherited,
s.stanullfrac AS null_frac,
s.stawidth AS avg_width,
s.stadistinct AS n_distinct,
CASE
WHEN s.stakind1 = 1 THEN s.stavalues1
WHEN s.stakind2 = 1 THEN s.stavalues2
WHEN s.stakind3 = 1 THEN s.stavalues3
WHEN s.stakind4 = 1 THEN s.stavalues4
WHEN s.stakind5 = 1 THEN s.stavalues5
END AS most_common_vals,
CASE
WHEN s.stakind1 = 1 THEN s.stanumbers1
WHEN s.stakind2 = 1 THEN s.stanumbers2
WHEN s.stakind3 = 1 THEN s.stanumbers3
WHEN s.stakind4 = 1 THEN s.stanumbers4
WHEN s.stakind5 = 1 THEN s.stanumbers5
END AS most_common_freqs,
CASE
WHEN s.stakind1 = 2 THEN s.stavalues1
WHEN s.stakind2 = 2 THEN s.stavalues2
WHEN s.stakind3 = 2 THEN s.stavalues3
WHEN s.stakind4 = 2 THEN s.stavalues4
WHEN s.stakind5 = 2 THEN s.stavalues5
END AS histogram_bounds,
CASE
WHEN s.stakind1 = 3 THEN s.stanumbers1[1]
WHEN s.stakind2 = 3 THEN s.stanumbers2[1]
WHEN s.stakind3 = 3 THEN s.stanumbers3[1]
WHEN s.stakind4 = 3 THEN s.stanumbers4[1]
WHEN s.stakind5 = 3 THEN s.stanumbers5[1]
END AS correlation,
CASE
WHEN s.stakind1 = 4 THEN s.stavalues1
WHEN s.stakind2 = 4 THEN s.stavalues2
WHEN s.stakind3 = 4 THEN s.stavalues3
WHEN s.stakind4 = 4 THEN s.stavalues4
WHEN s.stakind5 = 4 THEN s.stavalues5
END AS most_common_elems,
CASE
WHEN s.stakind1 = 4 THEN s.stanumbers1
WHEN s.stakind2 = 4 THEN s.stanumbers2
WHEN s.stakind3 = 4 THEN s.stanumbers3
WHEN s.stakind4 = 4 THEN s.stanumbers4
WHEN s.stakind5 = 4 THEN s.stanumbers5
END AS most_common_elem_freqs,
CASE
WHEN s.stakind1 = 5 THEN s.stanumbers1
WHEN s.stakind2 = 5 THEN s.stanumbers2
WHEN s.stakind3 = 5 THEN s.stanumbers3
WHEN s.stakind4 = 5 THEN s.stanumbers4
WHEN s.stakind5 = 5 THEN s.stanumbers5
END AS elem_count_histogram
FROM
(SELECT n.nspname,
c.relname,
a.attname,
(select stainherit from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stainherit,
(select stanullfrac from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanullfrac,
(select stawidth from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stawidth,
(select stadistinct from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stadistinct,
(select stakind1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind1,
(select stakind2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind2,
(select stakind3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind3,
(select stakind4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind4,
(select stakind5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stakind5,
(select stanumbers1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers1,
(select stanumbers2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers2,
(select stanumbers3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers3,
(select stanumbers4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers4,
(select stanumbers5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stanumbers5,
(select stavalues1 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues1,
(select stavalues2 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues2,
(select stavalues3 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues3,
(select stavalues4 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues4,
(select stavalues5 from pg_get_gtt_statistics(c.oid, a.attnum, ''::text)) as stavalues5
FROM
pg_class c
JOIN pg_attribute a ON c.oid = a.attrelid
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relpersistence='g' AND c.relkind in('r','p','i','t') and a.attnum > 0 and NOT a.attisdropped AND has_column_privilege(c.oid, a.attnum, 'select'::text)) s;
CREATE VIEW pg_stats AS
SELECT
nspname AS schemaname,
@ -366,8 +477,8 @@ WHERE
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
CASE WHEN pro.proisagg = true THEN 'aggregate'::text
WHEN pro.proisagg = false THEN 'function'::text
CASE WHEN pro.prokind = 'a' THEN 'aggregate'::text
WHEN pro.prokind != 'a' THEN 'function'::text
END AS objtype,
pro.pronamespace AS objnamespace,
CASE WHEN pg_function_is_visible(pro.oid)
@ -1545,8 +1656,8 @@ AS $$ SELECT CAST(float8out($1) AS VARCHAR2) $$
LANGUAGE SQL STRICT IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION to_char(TEXT)
RETURNS TEXT
AS $$ SELECT $1 $$
RETURNS varchar
AS $$ SELECT $1::varchar(10485760) $$
LANGUAGE SQL STRICT IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION to_number(TEXT)
@ -2752,7 +2863,7 @@ DECLARE
query_str_do_revoke text;
BEGIN
query_str_create_table := 'CREATE TABLE public.pgxc_copy_error_log
(relname varchar, begintime timestamptz, filename varchar, rownum int8, rawrecord text, detail text)';
(relname varchar, begintime timestamptz, filename varchar, lineno int8, rawrecord text, detail text)';
EXECUTE query_str_create_table;
query_str_create_index := 'CREATE INDEX copy_error_log_relname_idx ON public.pgxc_copy_error_log(relname)';

View File

@ -2267,6 +2267,20 @@ static Param* _copyParam(const Param* from)
return newnode;
}
/*
* _copyRownum
*/
static Rownum* _copyRownum(const Rownum* from)
{
Rownum* newnode = (Rownum*)makeNode(Rownum);
COPY_SCALAR_FIELD(rownumcollid);
COPY_LOCATION_FIELD(location);
return newnode;
}
/*
* _copyAggref
*/
@ -6011,6 +6025,9 @@ void* copyObject(const void* from)
case T_Param:
retval = _copyParam((Param*)from);
break;
case T_Rownum:
retval = _copyRownum((Rownum*)from);
break;
case T_Aggref:
retval = _copyAggref((Aggref*)from);
break;

View File

@ -1750,3 +1750,22 @@ List* list_merge_int(List* list1, List* list2)
return list_dst;
}
List* list_insert_nth_oid(List* list, int pos, Oid datum)
{
if (list == NIL) {
Assert(pos == 0);
return list_make1_oid(datum);
}
Assert(IsOidList(list));
if (pos == 0) { // add at first pos
list = lcons_oid(datum, list);
} else { // find cell at pos - 1, then add new cell after it;
ListCell* prevCell = list_nth_cell(list, pos - 1);
ListCell* newCell = add_new_cell(list, prevCell);
lfirst_oid(newCell) = datum;
}
check_list_invariants(list);
return list;
}

View File

@ -615,3 +615,36 @@ Param* makeParam(ParamKind paramkind, int paramid, Oid paramtype, int32 paramtyp
return argp;
}
/*
* makeIndexInfo
* create an IndexInfo node
*/
IndexInfo* makeIndexInfo(int numattrs, List* expressions, List* predicates, bool unique, bool isready, bool concurrent)
{
IndexInfo* n = makeNode(IndexInfo);
n->ii_NumIndexAttrs = numattrs;
n->ii_Unique = unique;
n->ii_ReadyForInserts = isready;
n->ii_Concurrent = concurrent;
/* expressions */
n->ii_Expressions = expressions;
n->ii_ExpressionsState = NIL;
/* predicates */
n->ii_Predicate = predicates;
n->ii_PredicateState = NULL;
/* exclusion constraints */
n->ii_ExclusionOps = NULL;
n->ii_ExclusionProcs = NULL;
n->ii_ExclusionStrats = NULL;
/* initialize index-build state to default */
n->ii_BrokenHotChain = false;
n->ii_PgClassAttrId = 0;
return n;
}

View File

@ -223,6 +223,9 @@ Oid exprType(const Node* expr)
case T_GroupingId:
type = INT4OID;
break;
case T_Rownum:
type = INT8OID;
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
@ -673,6 +676,9 @@ Oid exprCollation(const Node* expr)
case T_Const:
coll = ((const Const*)expr)->constcollid;
break;
case T_Rownum:
coll = ((const Rownum*)expr)->rownumcollid;
break;
case T_Param:
coll = ((const Param*)expr)->paramcollid;
break;
@ -900,6 +906,9 @@ void exprSetCollation(Node* expr, Oid collation)
case T_Const:
((Const*)expr)->constcollid = collation;
break;
case T_Rownum:
((Rownum*)expr)->rownumcollid = collation;
break;
case T_Param:
((Param*)expr)->paramcollid = collation;
break;
@ -1528,6 +1537,7 @@ bool expression_tree_walker(Node* node, bool (*walker)(), void* context)
case T_BitString:
case T_Null:
case T_PgFdwRemoteInfo:
case T_Rownum:
/* primitive node types with no expression subnodes */
break;
case T_Aggref: {
@ -2085,6 +2095,12 @@ Node* expression_tree_mutator(Node* node, Node* (*mutator)(Node*, void*), void*
/* XXX we don't bother with datumCopy; should we? */
return (Node*)newnode;
} break;
case T_Rownum: {
Rownum* oldnode = (Rownum*)node;
Rownum* newnode = NULL;
FLATCOPY(newnode, oldnode, Rownum, isCopy);
return (Node*)newnode;
} break;
case T_Param:
case T_CoerceToDomainValue:
case T_CaseTestExpr:

View File

@ -1952,6 +1952,14 @@ static void _outParam(StringInfo str, Param* node)
WRITE_TYPEINFO_FIELD(paramtype);
}
static void _outRownum(StringInfo str, const Rownum* node)
{
WRITE_NODE_TYPE("ROWNUM");
WRITE_OID_FIELD(rownumcollid);
WRITE_LOCATION_FIELD(location);
}
static void _outAggref(StringInfo str, Aggref* node)
{
WRITE_NODE_TYPE("AGGREF");
@ -4975,6 +4983,9 @@ static void _outNode(StringInfo str, const void* obj)
case T_Param:
_outParam(str, (Param*)obj);
break;
case T_Rownum:
_outRownum(str, (Rownum*)obj);
break;
case T_Aggref:
_outAggref(str, (Aggref*)obj);
break;

View File

@ -1541,6 +1541,18 @@ static Var* _readVar(void)
READ_DONE();
}
/*
* _readRownum
*/
static Rownum* _readRownum(void)
{
READ_LOCALS(Rownum);
READ_OID_FIELD(rownumcollid);
READ_LOCATION_FIELD(location);
READ_DONE();
}
/*
* _readConst
*/
@ -5182,6 +5194,8 @@ Node* parseNodeString(void)
return_value = _readSplitPartitionState();
} else if (MATCH("ADDPARTITIONSTATE", 17)) {
return_value = _readAddPartitionState();
} else if (MATCH("ROWNUM", 6)) {
return_value = _readRownum();
} else {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),

View File

@ -681,7 +681,7 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy
RANGE RAW READ REAL REASSIGN REBUILD RECHECK RECURSIVE REF REFERENCES REINDEX REJECT_P
RELATIVE_P RELEASE RELOPTIONS REMOTE_P RENAME REPEATABLE REPLACE REPLICA
RESET RESIZE RESOURCE RESTART RESTRICT RETURN RETURNING RETURNS REUSE REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
ROW ROWNUM ROWS RULE
SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHIPPABLE SHOW SHUTDOWN
@ -4184,20 +4184,8 @@ OptTemp: TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| TEMP { $$ = RELPERSISTENCE_TEMP; }
| LOCAL TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| LOCAL TEMP { $$ = RELPERSISTENCE_TEMP; }
| GLOBAL TEMPORARY
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = RELPERSISTENCE_TEMP;
}
| GLOBAL TEMP
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = RELPERSISTENCE_TEMP;
}
| GLOBAL TEMPORARY { $$ = RELPERSISTENCE_GLOBAL_TEMP; }
| GLOBAL TEMP { $$ = RELPERSISTENCE_GLOBAL_TEMP; }
| UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; }
| /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; }
;
@ -13646,19 +13634,13 @@ OptTempTableName:
}
| GLOBAL TEMPORARY opt_table qualified_name
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = $4;
$$->relpersistence = RELPERSISTENCE_TEMP;
$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
}
| GLOBAL TEMP opt_table qualified_name
{
ereport(WARNING,
(errmsg("GLOBAL is deprecated in temporary table creation"),
parser_errposition(@1)));
$$ = $4;
$$->relpersistence = RELPERSISTENCE_TEMP;
$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
}
| UNLOGGED opt_table qualified_name
{
@ -16109,6 +16091,12 @@ func_expr_common_subexpr:
n->call_func = false;
$$ = (Node *)n;
}
| ROWNUM
{
Rownum *r = makeNode(Rownum);
r->location = @1;
$$ = (Node *)r;
}
| CURRENT_ROLE
{
FuncCall *n = makeNode(FuncCall);
@ -18148,6 +18136,7 @@ reserved_keyword:
| WHERE
| WINDOW
| WITH
| ROWNUM
;
%%

View File

@ -762,8 +762,8 @@ static Node* build_coercion_expression(Node* node, CoercionPathType pathtype, Oi
* various binary-compatibility cases.
*/
AssertEreport(!procstruct->proretset, MOD_OPT, "function is not return set");
AssertEreport(!procstruct->proisagg, MOD_OPT, "function is not agg");
AssertEreport(!procstruct->proiswindow, MOD_OPT, "function is not window function");
AssertEreport(!PROC_IS_AGG(procstruct->prokind), MOD_OPT, "function is not agg");
AssertEreport(!PROC_IS_WIN(procstruct->prokind), MOD_OPT, "function is not window function");
nargs = procstruct->pronargs;
AssertEreport((nargs >= 1 && nargs <= 3), MOD_OPT, "The number of parameters in the function is incorrect.");
AssertEreport((nargs < 2 || procstruct->proargtypes.values[1] == INT4OID),

View File

@ -301,6 +301,7 @@ Node* transformExpr(ParseState* pstate, Node* expr)
case T_WindowFunc:
case T_ArrayRef:
case T_FuncExpr:
case T_Rownum:
case T_OpExpr:
case T_DistinctExpr:
case T_NullIfExpr:

View File

@ -1700,9 +1700,9 @@ FuncDetailCode func_get_detail(List* funcname, List* fargs, List* fargnames, int
}
*argdefaults = GetDefaultVale(*funcid, best_candidate->argnumbers, best_candidate->ndargs);
}
if (pform->proisagg) {
if (PROC_IS_AGG(pform->prokind)) {
result = FUNCDETAIL_AGGREGATE;
} else if (pform->proiswindow) {
} else if (PROC_IS_WIN(pform->prokind)) {
result = FUNCDETAIL_WINDOWFUNC;
} else {
result = FUNCDETAIL_NORMAL;
@ -2106,7 +2106,7 @@ Oid LookupAggNameTypeNames(List* aggname, List* argtypes, bool noError)
}
pform = (Form_pg_proc)GETSTRUCT(ftup);
if (!pform->proisagg) {
if (!PROC_IS_AGG(pform->prokind)) {
ReleaseSysCache(ftup);
if (noError)
return InvalidOid;

View File

@ -1482,6 +1482,9 @@ static int FigureColnameInternal(Node* node, char** name)
/* make GROUPING() act like a regular function */
*name = "grouping";
return 2;
case T_Rownum:
*name = "rownum";
return 2;
case T_SubLink:
switch (((SubLink*)node)->subLinkType) {
case EXISTS_SUBLINK:

View File

@ -826,7 +826,7 @@ bool IsTypeInBlacklist(Oid typoid)
switch (typoid) {
case LINEOID:
case XMLOID:
// case XMLOID:
case PGNODETREEOID:
isblack = true;
break;

View File

@ -166,6 +166,7 @@ static void transformTableLikeClause(
CreateStmtContext* cxt, TableLikeClause* table_like_clause, bool preCheck, bool isFirstNode = false);
static void transformTableLikePartitionProperty(Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns,
List* partitionList, List** partitionDefinitions);
static IntervalPartitionDefState* TransformTableLikeIntervalPartitionDef(HeapTuple partitionTableTuple);
static void transformTableLikePartitionKeys(
Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns, List** partKeyPosList);
static void transformTableLikePartitionBoundaries(
@ -220,6 +221,7 @@ static List* divide_start_end_every_internal(ParseState* pstate, char* partName,
static List* DividePartitionStartEndInterval(ParseState* pstate, Form_pg_attribute attr, char* partName,
Const* startVal, Const* endVal, Const* everyVal, Node* everyExpr, int* numPart, int maxNum);
static void TryReuseFilenode(Relation rel, CreateStmtContext *ctx, bool clonepart);
extern Node* makeAConst(Value* v, int location);
/*
* transformCreateStmt -
@ -441,7 +443,7 @@ List* transformCreateStmt(CreateStmt* stmt, const char* queryString, const List*
tblLlikeClause->relation->relpersistence == RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("do not support create non-temp table like temp table")));
errmsg("do not support create non-local-temp table like local temp table")));
break;
default:
@ -1537,14 +1539,12 @@ static void transformTableLikeClause(
n = makeNode(PartitionState);
n->partitionKey = partKeyColumns;
n->partitionList = partitionDefinitions;
#ifdef PGXC
// in mppdb, we do not support interval partition
n->intervalPartDef = NULL;
n->partitionStrategy = partitionForm->partstrategy;
#else
n->intervalPartDef = NULL;
n->partitionStrategy = partitionForm->partstrategy;
#endif
if (partitionForm->partstrategy == PART_STRATEGY_INTERVAL) {
n->intervalPartDef = TransformTableLikeIntervalPartitionDef(partitionTableTuple);
} else {
n->intervalPartDef = NULL;
}
n->rowMovement = relation->rd_rel->relrowmovement ? ROWMOVEMENT_ENABLE : ROWMOVEMENT_DISABLE;
// store the produced partition state in CreateStmtContext
@ -1611,6 +1611,12 @@ static void transformTableLikeClause(
reloptions = (Datum)0;
cxt->reloptions = untransformRelOptions(reloptions);
/* remove on_commit_delete_rows option */
if (cxt->relation->relpersistence != RELPERSISTENCE_TEMP &&
cxt->relation->relpersistence != RELPERSISTENCE_GLOBAL_TEMP) {
cxt->reloptions = RemoveRelOption(cxt->reloptions, "on_commit_delete_rows", NULL);
}
/* remove redis options first. */
RemoveRedisRelOptionsFromList(&(cxt->reloptions));
@ -1683,6 +1689,32 @@ static void transformTableLikePartitionProperty(Relation relation, HeapTuple par
transformTableLikePartitionBoundaries(relation, partKeyPosList, partitionList, partitionDefinitions);
}
static IntervalPartitionDefState* TransformTableLikeIntervalPartitionDef(HeapTuple partitionTableTuple)
{
IntervalPartitionDefState* intervalPartDef = makeNode(IntervalPartitionDefState);
Relation partitionRel = relation_open(PartitionRelationId, RowExclusiveLock);
char* intervalStr = ReadIntervalStr(partitionTableTuple, RelationGetDescr(partitionRel));
Assert(intervalStr != NULL);
intervalPartDef->partInterval = makeAConst(makeString(intervalStr), -1);
oidvector* tablespaceIdVec = ReadIntervalTablespace(partitionTableTuple, RelationGetDescr(partitionRel));
intervalPartDef->intervalTablespaces = NULL;
if (tablespaceIdVec != NULL && tablespaceIdVec->dim1 > 0) {
for (int i = 0; i < tablespaceIdVec->dim1; ++i) {
char* tablespaceName = get_tablespace_name(tablespaceIdVec->values[i]);
if (tablespaceName == NULL) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace with OID %u does not exist", tablespaceIdVec->values[i])));
}
intervalPartDef->intervalTablespaces =
lappend(intervalPartDef->intervalTablespaces, makeString(tablespaceName));
}
}
relation_close(partitionRel, RowExclusiveLock);
return intervalPartDef;
}
static void transformTableLikePartitionKeys(
Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns, List** partKeyPosList)
{
@ -1789,6 +1821,11 @@ static void transformTableLikePartitionBoundaries(
foreach (partitionCell, orderedPartitionList) {
HeapTuple partitionTuple = (HeapTuple)lfirst(partitionCell);
Form_pg_partition partitionForm = (Form_pg_partition)GETSTRUCT(partitionTuple);
/* no need to copy interval partition */
if (partitionForm->partstrategy == PART_STRATEGY_INTERVAL) {
continue;
}
bool attIsNull = false;
Datum tableSpace = (Datum)0;
Datum boundaries = (Datum)0;
@ -3477,6 +3514,7 @@ List* transformAlterTableStmt(Oid relid, AlterTableStmt* stmt, const char* query
cxt.stmtType = ALTER_TABLE;
}
cxt.relation = stmt->relation;
cxt.relation->relpersistence = RelationGetRelPersistence(rel);
cxt.rel = rel;
cxt.inhRelations = NIL;
cxt.isalter = true;
@ -4161,19 +4199,24 @@ void checkPartitionSynax(CreateStmt* stmt)
/* check interval synax */
if (stmt->partTableState->intervalPartDef) {
#ifdef PGXC
/* in mpp version, we close interval partition feature */
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("Range partitioned table with INTERVAL was forbidden"),
errhint("Only support pure range partitioned table")));
#endif
if (stmt->partTableState->partitionKey->length > 1) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("Range partitioned table with INTERVAL clause has more than one column"),
errhint("Only support one partition key for interval partition")));
}
if (!IsA(stmt->partTableState->intervalPartDef->partInterval, A_Const) ||
((A_Const*)stmt->partTableState->intervalPartDef->partInterval)->val.type != T_String) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
// errmsg("invalid input syntax for type %s: \"%s\"", datatype, str)));
errmsg("invalid input syntax for type interval")));
}
int32 typmod = -1;
Interval* interval = NULL;
A_Const* node = (A_Const*)stmt->partTableState->intervalPartDef->partInterval;
interval = char_to_interval(node->val.val.str, typmod);
pfree(interval);
}
}

View File

@ -81,12 +81,12 @@ my $funcName; #[1]
my $nargs; #[2]
my $strict; #[3]
my $retset; #[4]
my $prosrc; #[25]
my $prosrc; #[24]
my $prorettype; #[6]
foreach my $row (@{ $catalog{builtindata} })
{
if ($row =~ /_0\(([0-9A-Z]+)\),\s+_1\(\"(\S+)\"\),\s+_2\((\d+)\),\s+_3\((\w+)\),\s+_4\((\w+)\),\s+.+?_6\((\d+)\),.+?_25\(\"(\w+)\"\),/)
if ($row =~ /_0\(([0-9A-Z]+)\),\s+_1\(\"(\S+)\"\),\s+_2\((\d+)\),\s+_3\((\w+)\),\s+_4\((\w+)\),\s+.+?_6\((\d+)\),.+?_24\(\"(\w+)\"\),/)
{
$foid = $1;
$funcName = $2;

View File

@ -39,6 +39,7 @@
#include "pgxc/execRemote.h"
#endif
#include "storage/fd.h"
#include "threadpool/threadpool.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@ -1391,6 +1392,7 @@ static int64 calculate_partition_indexes_size(Oid part_table_oid, Oid part_oid)
}
list_free_ext(indexOids);
relation_close(part_table_rel, AccessShareLock);
return size;
}
@ -1821,10 +1823,13 @@ Datum pg_relation_filepath(PG_FUNCTION_ARGS)
switch (relform->relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. temp table is the same as unlogged table here.
case RELPERSISTENCE_TEMP:
backend = InvalidBackendId;
break;
case RELPERSISTENCE_GLOBAL_TEMP:
backend = BackendIdForTempRelations;
break;
default:
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

View File

@ -3198,7 +3198,7 @@ char* pg_get_functiondef_worker(Oid funcid, int* headerlines)
proc = (Form_pg_proc)GETSTRUCT(proctup);
name = NameStr(proc->proname);
if (proc->proisagg) {
if (PROC_IS_AGG(proc->prokind)) {
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("\"%s\" is an aggregate function", name)));
}
/* Need its pg_language tuple for the language name */
@ -3223,7 +3223,7 @@ char* pg_get_functiondef_worker(Oid funcid, int* headerlines)
/* Emit some miscellaneous options on one line */
oldlen = buf.len;
if (proc->proiswindow) {
if (PROC_IS_WIN(proc->prokind)) {
appendStringInfoString(&buf, " WINDOW");
}
switch (proc->provolatile) {
@ -3454,7 +3454,7 @@ static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool prin
}
/* Check for special treatment of ordered-set aggregates */
if (proc->proisagg) {
if (PROC_IS_AGG(proc->prokind)) {
Oid proc_tup_oid;
HeapTuple agg_tup;
Form_pg_aggregate agg_form;
@ -7445,6 +7445,10 @@ static void get_rule_expr(Node* node, deparse_context* context, bool showimplici
pfree_ext(tmp);
}
break;
case T_Rownum:
appendStringInfo(buf, "ROWNUM");
break;
case T_Const:
get_const_expr((Const*)node, context, 0);

View File

@ -112,6 +112,7 @@
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "catalog/pg_proc.h"
#include "catalog/storage_gtt.h"
#include "executor/executor.h"
#include "foreign/foreign.h"
#include "mb/pg_wchar.h"
@ -4754,18 +4755,23 @@ void examine_variable(PlannerInfo* root, Node* node, int var_relid, VariableStat
*/
char stakind = STARELKIND_CLASS;
Oid indexid = index->indexoid;
char relPersistence = get_rel_persistence(index->indexoid);
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data->statsTuple = NULL;
var_data->freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data->statsTuple = get_gtt_att_statistic(index->indexoid,
Int16GetDatum(pos + 1));
var_data->freefunc = release_gtt_statistic_cache;
} else {
var_data->statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(indexid),
CharGetDatum(stakind),
Int16GetDatum(pos + 1),
BoolGetDatum(false));
var_data->freefunc = ReleaseSysCache;
}
var_data->freefunc = ReleaseSysCache;
if (HeapTupleIsValid(var_data->statsTuple)) {
/* Get index's table for permission check */
RangeTblEntry *rte;
@ -4853,17 +4859,22 @@ static void examine_simple_variable(PlannerInfo* root, Var* var, VariableStatDat
*
* We do not search system cache in upgrading
*/
char relPersistence = get_rel_persistence(rte->relid);
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data->statsTuple = NULL;
var_data->freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data->statsTuple = get_gtt_att_statistic(rte->relid, var->varattno);
var_data->freefunc = release_gtt_statistic_cache;
} else {
var_data->statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(sta_relid),
CharGetDatum(sta_kind),
Int16GetDatum(var->varattno),
BoolGetDatum(rte->inh));
var_data->freefunc = ReleaseSysCache;
}
var_data->freefunc = ReleaseSysCache;
if (HeapTupleIsValid(var_data->statsTuple)) {
/* check if user has permission to read this column */
var_data->aclOk = (pg_class_aclcheck(rte->relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK) ||
@ -5800,7 +5811,6 @@ static Pattern_Prefix_Status regex_fixed_prefix(
/* Use the regexp machinery to extract the prefix, if any */
prefix = regexp_fixed_prefix(DatumGetTextPP(patt_const->constvalue), case_insensitive, collation, &exact);
if (prefix == NULL) {
*prefix_const = NULL;
@ -6851,7 +6861,7 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (index->indexkeys[0] != 0) {
/* Simple variable --- look to stats for the underlying table */
RangeTblEntry* rte = planner_rt_fetch(index->rel->relid, root);
char relPersistence = get_rel_persistence(rte->relid);
Assert(rte->rtekind == RTE_RELATION);
relid = rte->relid;
Assert(relid != InvalidOid);
@ -6868,16 +6878,22 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data.statsTuple = NULL;
var_data.freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data.statsTuple = get_gtt_att_statistic(rte->relid, col_num);
var_data.freefunc = release_gtt_statistic_cache;
} else {
var_data.statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(staoid),
CharGetDatum(stakind),
Int16GetDatum(col_num),
BoolGetDatum(rte->inh));
var_data.freefunc = ReleaseSysCache;
}
var_data.freefunc = ReleaseSysCache;
} else {
/* Expression --- maybe there are stats for the index itself */
char relPersistence = get_rel_persistence(index->indexoid);
relid = index->indexoid;
col_num = 1;
@ -6892,14 +6908,19 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
var_data.statsTuple = NULL;
var_data.freefunc = ReleaseSysCache;
} else if (relPersistence == RELPERSISTENCE_GLOBAL_TEMP) {
var_data.statsTuple = get_gtt_att_statistic(relid, col_num);
var_data.freefunc = release_gtt_statistic_cache;
} else {
var_data.statsTuple = SearchSysCache4(STATRELKINDATTINH,
ObjectIdGetDatum(staoid),
CharGetDatum(stakind),
Int16GetDatum(col_num),
BoolGetDatum(false));
var_data.freefunc = ReleaseSysCache;
}
var_data.freefunc = ReleaseSysCache;
}
if (HeapTupleIsValid(var_data.statsTuple)) {
@ -8420,7 +8441,6 @@ void set_noanalyze_rellist(Oid relid, AttrNumber attid)
* so only check the statistics of foreign table. do not check column statistic.
*/
Relation rel = relation_open(relid, AccessShareLock);
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isSpecifiedSrvTypeFromRelId(relid, OBS_SERVER)) {
is_obs_ft = true;
}

View File

@ -2546,10 +2546,8 @@ Datum timestamp_larger(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMP(result);
}
Datum timestamp_mi(PG_FUNCTION_ARGS)
Datum timestamp_mi(Timestamp dt1, Timestamp dt2)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Interval* result = NULL;
result = (Interval*)palloc(sizeof(Interval));
@ -2593,6 +2591,13 @@ Datum timestamp_mi(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
Datum timestamp_mi(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
return timestamp_mi(dt1, dt2);
}
/*
* interval_justify_interval()
*
@ -2732,20 +2737,8 @@ Datum interval_justify_days(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
/* timestamp_pl_interval()
* Add a interval to a timestamp data type.
* Note that interval has provisions for qualitative year/month and day
* units, so try to do the right thing with them.
* To add a month, increment the month, and use the same day of month.
* Then, if the next month has fewer days, set the day of month
* to the last day of month.
* To add a day, increment the mday, and use the same time of day.
* Lastly, add in the "quantitative time".
*/
Datum timestamp_pl_interval(PG_FUNCTION_ARGS)
Datum timestamp_pl_interval(Timestamp timestamp, Interval* span)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval* span = PG_GETARG_INTERVAL_P(1);
Timestamp result;
if (TIMESTAMP_NOT_FINITE(timestamp)) {
@ -2803,10 +2796,25 @@ Datum timestamp_pl_interval(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMP(result);
}
Datum timestamp_mi_interval(PG_FUNCTION_ARGS)
/* timestamp_pl_interval()
* Add a interval to a timestamp data type.
* Note that interval has provisions for qualitative year/month and day
* units, so try to do the right thing with them.
* To add a month, increment the month, and use the same day of month.
* Then, if the next month has fewer days, set the day of month
* to the last day of month.
* To add a day, increment the mday, and use the same time of day.
* Lastly, add in the "quantitative time".
*/
Datum timestamp_pl_interval(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval* span = PG_GETARG_INTERVAL_P(1);
return timestamp_pl_interval(timestamp, span);
}
Datum timestamp_mi_interval(Timestamp timestamp, Interval* span)
{
Interval tspan;
tspan.month = -span->month;
@ -2816,6 +2824,13 @@ Datum timestamp_mi_interval(PG_FUNCTION_ARGS)
return DirectFunctionCall2(timestamp_pl_interval, TimestampGetDatum(timestamp), PointerGetDatum(&tspan));
}
Datum timestamp_mi_interval(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
Interval* span = PG_GETARG_INTERVAL_P(1);
return timestamp_mi_interval(timestamp, span);
}
/* timestamptz_pl_interval()
* Add a interval to a timestamp with time zone data type.
* Note that interval has provisions for qualitative year/month
@ -2981,15 +2996,8 @@ Datum interval_mi(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
/*
* There is no interval_abs(): it is unclear what value to return:
* http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
* http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
*/
Datum interval_mul(PG_FUNCTION_ARGS)
Datum interval_mul(Interval* span, float8 factor)
{
Interval* span = PG_GETARG_INTERVAL_P(0);
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder_days, sec_remainder;
int32 orig_month = span->month;
int32 orig_day = span->day;
@ -3051,6 +3059,18 @@ Datum interval_mul(PG_FUNCTION_ARGS)
PG_RETURN_INTERVAL_P(result);
}
/*
* There is no interval_abs(): it is unclear what value to return:
* http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
* http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
*/
Datum interval_mul(PG_FUNCTION_ARGS)
{
Interval* span = PG_GETARG_INTERVAL_P(0);
float8 factor = PG_GETARG_FLOAT8(1);
return interval_mul(span, factor);
}
Datum mul_d_interval(PG_FUNCTION_ARGS)
{
/* Args are float8 and Interval *, but leave them as generic Datum */

View File

@ -572,6 +572,12 @@ Datum varchar(PG_FUNCTION_ARGS)
/* only reach here if string is too long... */
if (len > MaxAttrSize) {
ereport(ERROR,
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
errmsg("value too long for type character varying maxlen(%d) input_len(%d)", MaxAttrSize, len)));
}
/* truncate multibyte string preserving multibyte boundary */
max_mb_len = pg_mbcharcliplen(s_data, len, max_len);

View File

@ -1421,12 +1421,12 @@ void xml_ereport(PgXmlErrorContext* errcxt, int level, int sqlcode, const char*
/*
* Error handler for libxml errors and warnings
*/
static void xml_errorHandler(void* data, xmlErrorPtr error)
static void xml_error_handler(void* data, xmlErrorPtr error)
{
PgXmlErrorContext* xml_errcxt = (PgXmlErrorContext*)data;
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)error->ctxt;
xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;
xmlNodePtr node = error->node;
xmlNodePtr node = (xmlNodePtr)error->node;
const xmlChar* name = (node != NULL && node->type == XML_ELEMENT_NODE) ? node->name : NULL;
int domain = error->domain;
int level = error->level;
@ -1862,12 +1862,12 @@ char* map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
if (TIMESTAMP_NOT_FINITE(time_stamp)) {
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("time_stamp out of range"),
errdetail("XML does not support infinite time_stamp values.")));
errmsg("timestamp out of range"),
errdetail("XML does not support infinite timestamp values.")));
} else if (timestamp2tm(time_stamp, NULL, &tm, &fsec, NULL, NULL) == 0) {
EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
} else {
ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time_stamp out of range")));
ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));
}
return pstrdup(buf);
}
@ -1885,12 +1885,12 @@ char* map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
if (TIMESTAMP_NOT_FINITE(time_stamp)) {
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("time_stamp out of range"),
errdetail("XML does not support infinite time_stamp values.")));
errmsg("timestamp out of range"),
errdetail("XML does not support infinite timestamp values.")));
} else if (timestamp2tm(time_stamp, &tz, &tm, &fsec, &tzn, NULL) == 0) {
EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
} else {
ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("time_stamp out of range")));
ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range")));
}
return pstrdup(buf);
}
@ -1915,7 +1915,7 @@ char* map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
if (writer == NULL || xml_errcxt->err_occurred) {
xml_ereport(xml_errcxt, ERROR, ERRCODE_OUT_OF_MEMORY, "could not allocate xmlTextWriter");
}
if (xmlbinary == XMLBINARY_BASE64) {
if (u_sess->attr.attr_common.xmlbinary == XMLBINARY_BASE64) {
xmlTextWriterWriteBase64(writer, VARDATA_ANY(b_str), 0, VARSIZE_ANY_EXHDR(b_str));
} else {
xmlTextWriterWriteBinHex(writer, VARDATA_ANY(b_str), 0, VARSIZE_ANY_EXHDR(b_str));

View File

@ -697,6 +697,25 @@ void AtEOXact_CatCache(bool is_commit)
#endif
}
/*
* Standard routine for creating cache context if it doesn't exist yet
*
* There are a lot of places (probably far more than necessary) that check
* whether CacheMemoryContext exists yet and want to create it if not.
* We centralize knowledge of exactly how to create it here.
*/
void CreateCacheMemoryContext(void)
{
/*
* Purely for paranoia, check that context doesn't exist; caller probably
* did so already.
*/
if (!CacheMemoryContext)
CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
"CacheMemoryContext",
ALLOCSET_DEFAULT_SIZES);
}
/*
* reset_catalog_cache
*
@ -1825,8 +1844,7 @@ HeapTuple CreateHeapTuple4BuiltinFunc(const Builtin_func* func, TupleDesc desc)
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(func->prorows);
values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(func->protransform);
values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(func->proisagg);
values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(func->proiswindow);
values[Anum_pg_proc_prokind - 1] = CharGetDatum(func->prokind);
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(func->prosecdef);
values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(func->proleakproof);
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(func->strict);
@ -2009,7 +2027,7 @@ List* SearchBuiltinProcCacheList(CatCache* cache, int nkey, Datum* arguments, Li
TupleDesc CreateTupDesc4BuiltinFuncWithOid()
{
TupleDesc tupdesc = CreateTemplateTupleDesc(32, false);
TupleDesc tupdesc = CreateTemplateTupleDesc(31, false);
TupleDescInitEntry(tupdesc, (AttrNumber)1, "proname", NAMEOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)2, "pronamespace", OIDOID, -1, 0);
@ -2019,30 +2037,29 @@ TupleDesc CreateTupDesc4BuiltinFuncWithOid()
TupleDescInitEntry(tupdesc, (AttrNumber)6, "prorows", FLOAT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)7, "provariadic", OIDOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)8, "protransform", REGPROCOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)9, "proisagg", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)10, "proiswindow", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)11, "prosecdef", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)12, "proleakproof", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)13, "proisstrict", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)14, "proretset", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)15, "provolatile", CHAROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)16, "pronargs", INT2OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)17, "pronargdefaults", INT2OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)18, "prorettype", OIDOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)19, "proargtypes", OIDVECTOROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)20, "proallargtypes", INT4ARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)21, "proargmodes", CHARARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)22, "proargnames", TEXTARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)23, "proargdefaults", PGNODETREEOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)24, "prosrc", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)25, "probin", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)26, "proconfig", TEXTARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)27, "proacl", ACLITEMARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)28, "prodefaultargpos", INT2VECTOROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)29, "fencedmode", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)30, "proshippable", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)31, "propackage", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)32, "oid", OIDOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)9, "prokind", CHAROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)10, "prosecdef", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)11, "proleakproof", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)12, "proisstrict", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)13, "proretset", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)14, "provolatile", CHAROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)15, "pronargs", INT2OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)16, "pronargdefaults", INT2OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)17, "prorettype", OIDOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)18, "proargtypes", OIDVECTOROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)19, "proallargtypes", INT4ARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)20, "proargmodes", CHARARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)21, "proargnames", TEXTARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)22, "proargdefaults", PGNODETREEOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)23, "prosrc", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)24, "probin", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)25, "proconfig", TEXTARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)26, "proacl", ACLITEMARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)27, "prodefaultargpos", INT2VECTOROID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)28, "fencedmode", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)29, "proshippable", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)30, "propackage", BOOLOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)31, "oid", OIDOID, -1, 0);
return tupdesc;
}

View File

@ -47,6 +47,7 @@
#include "catalog/pg_app_workloadgroup_mapping.h"
#include "catalog/namespace.h"
#endif
#include "catalog/storage_gtt.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@ -1520,7 +1521,7 @@ Oid get_func_lang(Oid funcid)
/*
* get_func_iswindow
* Given procedure id, return the function's proiswindow field.
* Given procedure id, return the function is window or not.
*/
bool get_func_iswindow(Oid funcid)
{
@ -1530,7 +1531,7 @@ bool get_func_iswindow(Oid funcid)
if (!HeapTupleIsValid(tp)) {
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", funcid)));
}
result = ((Form_pg_proc)GETSTRUCT(tp))->proiswindow;
result = PROC_IS_WIN(((Form_pg_proc)GETSTRUCT(tp))->prokind);
ReleaseSysCache(tp);
return result;
}
@ -1912,6 +1913,27 @@ Oid get_rel_tablespace(Oid relid)
}
}
/*
* get_rel_persistence
*
* Returns the relpersistence associated with a given relation.
*/
char get_rel_persistence(Oid relid)
{
HeapTuple tp;
Form_pg_class reltup;
char result;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for relation %u", relid);
reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relpersistence;
ReleaseSysCache(tp);
return result;
}
/*
* get_typisdefined
*
@ -4073,6 +4095,18 @@ int32 get_attavgwidth(Oid relid, AttrNumber attnum, bool ispartition)
if (u_sess->attr.attr_common.upgrade_mode != 0) {
return 0;
}
if (!ispartition && get_rel_persistence(relid) == RELPERSISTENCE_GLOBAL_TEMP) {
tp = get_gtt_att_statistic(relid, attnum);
if (!HeapTupleIsValid(tp)) {
return 0;
}
stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
if (stawidth > 0) {
return stawidth;
} else {
return 0;
}
}
tp = SearchSysCache4(
STATRELKINDATTINH, ObjectIdGetDatum(relid), CharGetDatum(stakind), Int16GetDatum(attnum), BoolGetDatum(false));
if (HeapTupleIsValid(tp)) {
@ -4710,7 +4744,7 @@ bool is_not_strict_agg(Oid funcOid)
return false;
}
func_form = (Form_pg_proc)GETSTRUCT(func_tuple);
if (func_form->proisstrict == false && func_form->proisagg == false) {
if (func_form->proisstrict == false && !PROC_IS_AGG(func_form->prokind)) {
ReleaseSysCache(func_tuple);
return true;
}

View File

@ -368,6 +368,36 @@ Partition PartitionIdGetPartition(Oid partitionId)
return pd;
}
char* PartitionOidGetName(Oid partOid)
{
HeapTuple tuple = ScanPgPartition(partOid, true);
if (!HeapTupleIsValid(tuple)) {
return NULL;
}
Form_pg_partition part = (Form_pg_partition)GETSTRUCT(tuple);
char* relName = (char*)palloc0(NAMEDATALEN);
error_t rc = strncpy_s(relName, NAMEDATALEN, part->relname.data, NAMEDATALEN - 1);
securec_check_ss(rc, "\0", "\0");
heap_freetuple_ext(tuple);
return relName;
}
Oid PartitionOidGetTablespace(Oid partOid)
{
HeapTuple tuple = ScanPgPartition(partOid, true);
if (!HeapTupleIsValid(tuple)) {
return InvalidOid;
}
Form_pg_partition part = (Form_pg_partition)GETSTRUCT(tuple);
Oid tablespaceOid = part->reltablespace;
heap_freetuple_ext(tuple);
return tablespaceOid;
}
void PartitionClose(Partition partition)
{
/* Note: no locking manipulations needed */

View File

@ -112,6 +112,7 @@
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "catalog/pg_extension_data_source.h"
#include "catalog/storage_gtt.h"
#include "commands/sec_rls_cmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
@ -132,6 +133,7 @@
#include "rewrite/rewriteRlsPolicy.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "threadpool/threadpool.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@ -148,6 +150,8 @@
#include "utils/partitionmap_gs.h"
#include "utils/resowner.h"
#include "access/cstore_am.h"
#include "nodes/nodeFuncs.h"
#include "nodes/makefuncs.h"
/*
* name of relcache init file(s), used to speed up backend startup
@ -1693,10 +1697,27 @@ static Relation relation_build_desc(Oid targetRelId, bool insertIt, bool buildke
switch (relation->rd_rel->relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
relation->rd_backend = InvalidBackendId;
relation->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
relation->rd_backend = InvalidBackendId;
relation->rd_islocaltemp = true;
break;
case RELPERSISTENCE_GLOBAL_TEMP: // global temp table
{
BlockNumber relpages = 0;
double reltuples = 0;
BlockNumber relallvisible = 0;
relation->rd_backend = BackendIdForTempRelations;
relation->rd_islocaltemp = false;
get_gtt_relstats(RelationGetRelid(relation), &relpages, &reltuples, &relallvisible, NULL);
relation->rd_rel->relpages = static_cast<float8>(relpages);
relation->rd_rel->reltuples = static_cast<float8>(reltuples);
relation->rd_rel->relallvisible = static_cast<int4>(relallvisible);
}
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -1961,7 +1982,16 @@ static void relation_init_physical_addr(Relation relation)
heap_freetuple_ext(phys_tuple);
}
relation->rd_node.relNode = relation->rd_rel->relfilenode;
if (RELATION_IS_GLOBAL_TEMP(relation)) {
Oid newrelnode = gtt_fetch_current_relfilenode(RelationGetRelid(relation));
if (newrelnode != InvalidOid && newrelnode != relation->rd_rel->relfilenode) {
relation->rd_node.relNode = newrelnode;
} else {
relation->rd_node.relNode = relation->rd_rel->relfilenode;
}
} else {
relation->rd_node.relNode = relation->rd_rel->relfilenode;
}
} else {
/* Consult the relation mapper */
relation->rd_node.relNode = RelationMapOidToFilenode(relation->rd_id, relation->rd_rel->relisshared);
@ -2735,6 +2765,8 @@ static void relation_reload_index_info(Relation relation)
HeapTupleSetXmin(relation->rd_indextuple, HeapTupleGetRawXmin(tuple));
ReleaseSysCache(tuple);
gtt_fix_index_state(relation);
}
/* Okay, now it's valid again */
@ -2798,18 +2830,21 @@ static void relation_destroy_partition_map(Relation relation)
/* first free partKeyNum/partitionKeyDataType/ranges in the range map */
if (range_map->partitionKey) {
pfree_ext(range_map->partitionKey);
range_map->partitionKey = NULL;
}
if (range_map->partitionKeyDataType) {
pfree_ext(range_map->partitionKeyDataType);
range_map->partitionKeyDataType = NULL;
}
if (range_map->intervalValue) {
pfree_ext(range_map->intervalValue);
}
if (range_map->intervalTablespace) {
pfree_ext(range_map->intervalTablespace);
}
if (range_map->rangeElements) {
partition_map_destroy_range_array(range_map->rangeElements, range_map->rangeElementsNum);
}
}
pfree_ext(relation->partMap);
relation->partMap = NULL;
return;
}
@ -3672,10 +3707,16 @@ Relation RelationBuildLocalRelation(const char* relname, Oid relnamespace, Tuple
switch (relpersistence) {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
rel->rd_backend = InvalidBackendId;
rel->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP: // @Temp Table. Temp table here is just like unlogged table.
rel->rd_backend = InvalidBackendId;
rel->rd_islocaltemp = true;
break;
case RELPERSISTENCE_GLOBAL_TEMP: // global temp table
rel->rd_backend = BackendIdForTempRelations;
rel->rd_islocaltemp = false;
break;
default:
ereport(ERROR,
@ -3815,8 +3856,8 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
Datum values[Natts_pg_class];
bool nulls[Natts_pg_class];
bool replaces[Natts_pg_class];
errno_t rc;
errno_t rc = EOK;
bool modifyPgClass = !RELATION_IS_GLOBAL_TEMP(relation);
/* Indexes, sequences must have Invalid frozenxid; other rels must not */
Assert(((relation->rd_rel->relkind == RELKIND_INDEX || relation->rd_rel->relkind == RELKIND_SEQUENCE)
? freezeXid == InvalidTransactionId : TransactionIdIsNormal(freezeXid)) ||
@ -3850,17 +3891,22 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
}
}
/*
* Get a writable copy of the pg_class tuple for the given relation.
*/
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(RelationGetRelid(relation)));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not find tuple for relation %u", RelationGetRelid(relation))));
classform = (Form_pg_class)GETSTRUCT(tuple);
if (modifyPgClass) {
/*
* Get a writable copy of the pg_class tuple for the given relation.
*/
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(RelationGetRelid(relation)));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not find tuple for relation %u", RelationGetRelid(relation))));
}
classform = (Form_pg_class) GETSTRUCT(tuple);
} else {
memset_s(&classform, sizeof(classform), 0, sizeof(classform));
securec_check(rc, "\0", "\0");
}
ereport(LOG,
(errmsg("Relation %s(%u) set newfilenode %u oldfilenode %u xid %lu",
@ -3880,52 +3926,58 @@ void RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid, bool
newrnode.node.relNode = newrelfilenode;
newrnode.backend = relation->rd_backend;
RelationCreateStorage(
newrnode.node, relation->rd_rel->relpersistence, relation->rd_rel->relowner, relation->rd_bucketoid);
newrnode.node, relation->rd_rel->relpersistence, relation->rd_rel->relowner, relation->rd_bucketoid, relation);
smgrclosenode(newrnode);
/*
* Schedule unlinking of the old storage at transaction commit.
*/
RelationDropStorage(relation, isDfsTruncate);
if (!modifyPgClass) {
Oid relnode = gtt_fetch_current_relfilenode(RelationGetRelid(relation));
Assert(RELATION_IS_GLOBAL_TEMP(relation));
Assert(!RelationIsMapped(relation));
relation->rd_node.relNode = relnode;
CacheInvalidateRelcache(relation);
} else {
/*
* Now update the pg_class row. However, if we're dealing with a mapped
* index, pg_class.relfilenode doesn't change; instead we have to send the
* update to the relation mapper.
*/
if (RelationIsMapped(relation))
RelationMapUpdateMap(RelationGetRelid(relation), newrelfilenode, relation->rd_rel->relisshared, false);
else
classform->relfilenode = newrelfilenode;
/*
* Now update the pg_class row. However, if we're dealing with a mapped
* index, pg_class.relfilenode doesn't change; instead we have to send the
* update to the relation mapper.
*/
if (RelationIsMapped(relation))
RelationMapUpdateMap(RelationGetRelid(relation), newrelfilenode, relation->rd_rel->relisshared, false);
else
classform->relfilenode = newrelfilenode;
/* These changes are safe even for a mapped relation */
if (relation->rd_rel->relkind != RELKIND_SEQUENCE) {
classform->relpages = 0; /* it's empty until further notice */
classform->reltuples = 0;
classform->relallvisible = 0;
}
/* set classform's relfrozenxid and relfrozenxid64 */
classform->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
/* These changes are safe even for a mapped relation */
if (relation->rd_rel->relkind != RELKIND_SEQUENCE) {
classform->relpages = 0; /* it's empty until further notice */
classform->reltuples = 0;
classform->relallvisible = 0;
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "\0", "\0");
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "\0", "\0");
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
securec_check(rc, "\0", "\0");
replaces[Anum_pg_class_relfrozenxid64 - 1] = true;
values[Anum_pg_class_relfrozenxid64 - 1] = TransactionIdGetDatum(freezeXid);
nctup = heap_modify_tuple(tuple, RelationGetDescr(pg_class), values, nulls, replaces);
simple_heap_update(pg_class, &nctup->t_self, nctup);
CatalogUpdateIndexes(pg_class, nctup);
heap_freetuple_ext(nctup);
heap_freetuple_ext(tuple);
heap_close(pg_class, RowExclusiveLock);
}
/* set classform's relfrozenxid and relfrozenxid64 */
classform->relfrozenxid = (ShortTransactionId)InvalidTransactionId;
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "\0", "\0");
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "\0", "\0");
rc = memset_s(replaces, sizeof(replaces), false, sizeof(replaces));
securec_check(rc, "\0", "\0");
replaces[Anum_pg_class_relfrozenxid64 - 1] = true;
values[Anum_pg_class_relfrozenxid64 - 1] = TransactionIdGetDatum(freezeXid);
nctup = heap_modify_tuple(tuple, RelationGetDescr(pg_class), values, nulls, replaces);
simple_heap_update(pg_class, &nctup->t_self, nctup);
CatalogUpdateIndexes(pg_class, nctup);
heap_freetuple_ext(nctup);
heap_freetuple_ext(tuple);
heap_close(pg_class, RowExclusiveLock);
/*
* Make the pg_class row change visible, as well as the relation map
@ -5067,6 +5119,45 @@ List* RelationGetIndexExpressions(Relation relation)
return result;
}
/*
* RelationGetDummyIndexExpressions -- get dummy expressions for an index
*
* Return a list of dummy expressions (just Const nodes) with the same
* types/typmods/collations as the index's real expressions. This is
* useful in situations where we don't want to run any user-defined code.
*/
List* RelationGetDummyIndexExpressions(Relation relation)
{
List* result;
Datum exprsDatum;
bool isnull;
char* exprsString;
List* rawExprs;
ListCell* lc;
/* Quick exit if there is nothing to do. */
if (relation->rd_indextuple == NULL || heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL)) {
return NIL;
}
/* Extract raw node tree(s) from index tuple. */
exprsDatum = heap_getattr(relation->rd_indextuple, Anum_pg_index_indexprs, get_pg_index_descriptor(), &isnull);
Assert(!isnull);
exprsString = TextDatumGetCString(exprsDatum);
rawExprs = (List*)stringToNode(exprsString);
pfree(exprsString);
/* Construct null Consts; the typlen and typbyval are arbitrary. */
result = NIL;
foreach (lc, rawExprs) {
Node* rawExpr = (Node*)lfirst(lc);
result = lappend(
result, makeConst(exprType(rawExpr), exprTypmod(rawExpr), exprCollation(rawExpr), 1, (Datum)0, true, true));
}
return result;
}
/*
* RelationGetIndexPredicate -- get the index predicate for an index
*

View File

@ -92,6 +92,7 @@
#include <execinfo.h>
#include "tcop/stmt_retry.h"
#include "replication/walsender.h"
#undef _
#define _(x) err_gettext(x)
@ -3300,6 +3301,9 @@ static void send_message_to_frontend(ErrorData* edata)
if (edata->elevel == FATAL)
t_thrd.log_cxt.flush_message_immediately = true;
}
if (AM_WAL_DB_SENDER) {
ReadyForQuery((CommandDest)t_thrd.postgres_cxt.whereToSendOutput);
}
}
/*

View File

@ -40,6 +40,7 @@
#include "access/dfs/dfs_insert.h"
#include "catalog/namespace.h"
#include "catalog/pgxc_group.h"
#include "catalog/storage_gtt.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "commands/vacuum.h"
@ -3560,8 +3561,6 @@ static void init_configure_names_bool()
NULL
},
#endif
#ifdef ENABLE_MULTIPLE_NODES
{
{
"enable_slot_log",
@ -3576,7 +3575,6 @@ static void init_configure_names_bool()
NULL,
NULL
},
#endif
#ifdef ENABLE_MULTIPLE_NODES
{
{
@ -4597,6 +4595,38 @@ void set_qunit_case_number_hook(int newval, void* extra)
static void init_configure_names_int()
{
struct config_int local_configure_names_int[] = {
{
{
"max_active_global_temporary_table",
PGC_USERSET,
UNGROUPED,
gettext_noop("max active global temporary table."),
NULL
},
&u_sess->attr.attr_storage.max_active_gtt,
1000,
0,
1000000,
NULL,
NULL,
NULL
},
{
{
"vacuum_gtt_defer_check_age",
PGC_USERSET,
CLIENT_CONN_STATEMENT,
gettext_noop("The defer check age of GTT, used to check expired data after vacuum."),
NULL
},
&u_sess->attr.attr_storage.vacuum_gtt_defer_check_age,
10000,
0,
1000000,
NULL,
NULL,
NULL
},
{
{
"archive_timeout",
@ -5237,7 +5267,7 @@ static void init_configure_names_int()
GUC_UNIT_BLOCKS
},
&u_sess->attr.attr_storage.num_temp_buffers,
1024,
128,
100,
INT_MAX / 2,
check_temp_buffers,
@ -6435,7 +6465,6 @@ static void init_configure_names_int()
NULL,
NULL
},
#ifdef ENABLE_MULTIPLE_NODES
{
/* see max_connections */
{
@ -6453,7 +6482,6 @@ static void init_configure_names_int()
NULL,
NULL
},
#endif
{
{
"recovery_time_target",
@ -8804,7 +8832,6 @@ static void init_configure_names_int()
NULL,
NULL
},
#ifdef ENABLE_MULTIPLE_NODES
{
{
"max_changes_in_memory",
@ -8821,8 +8848,6 @@ static void init_configure_names_int()
NULL,
NULL
},
#endif
#ifdef ENABLE_MULTIPLE_NODES
{
{
"max_cached_tuplebufs",
@ -8839,7 +8864,6 @@ static void init_configure_names_int()
NULL,
NULL
},
#endif
{
{
"table_skewness_warning_rows",
@ -9075,6 +9099,22 @@ static void init_configure_names_int()
NULL,
NULL
},
{
{
"max_keep_log_seg",
PGC_SUSET,
WAL,
gettext_noop("Sets the threshold for implementing logical replication flow control."),
NULL
},
&g_instance.attr.attr_storage.max_keep_log_seg,
0,
0,
INT_MAX,
NULL,
NULL,
NULL
},
/* End-of-list marker */
{
{
@ -17868,7 +17908,7 @@ static bool check_temp_buffers(int* newval, void** extra, GucSource source)
/*
* Once local buffers have been initialized, it's too late to change this.
*/
if (t_thrd.storage_cxt.NLocBuffer && t_thrd.storage_cxt.NLocBuffer != *newval) {
if (u_sess->storage_cxt.NLocBuffer && u_sess->storage_cxt.NLocBuffer != *newval) {
GUC_check_errdetail(
"\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
return false;

View File

@ -258,6 +258,12 @@ max_wal_senders = 4 # max number of walsender processes
# (change requires restart)
wal_keep_segments = 16 # in logfile segments, 16MB each; 0 disables
#wal_sender_timeout = 6s # in milliseconds; 0 disables
enable_slot_log = off
max_replication_slots = 8 # max number of replication slots.i
# The value is classically set to 8.
# (change requires restart)
#max_changes_in_memory = 4096
#max_cached_tuplebufs = 8192
#replconninfo1 = '' # replication connection information used to connect primary on standby, or standby on primary,
# or connect primary or standby on secondary

View File

@ -57,6 +57,7 @@ MemoryContext StreamInfoContext = NULL;
* of these contexts, refer to src/backend/utils/mmgr/README
*/
THR_LOCAL MemoryContext ErrorContext = NULL;
THR_LOCAL MemoryContext CacheMemoryContext = NULL;
THR_LOCAL MemoryContext SelfMemoryContext = NULL;
THR_LOCAL MemoryContext TopMemoryContext = NULL;
THR_LOCAL MemoryContext AlignMemoryContext = NULL;

View File

@ -6765,7 +6765,7 @@ static Datum pl_coerce_type_typmod(Datum value, Oid targetTypeId, int32 targetTy
* various binary-compatibility cases.
*/
nargs = procstruct->pronargs;
AssertEreport(!procstruct->proretset && !procstruct->proisagg && !procstruct->proiswindow,
AssertEreport(!procstruct->proretset && !PROC_IS_AGG(procstruct->prokind) && !PROC_IS_WIN(procstruct->prokind),
MOD_PLSQL,
"It should not be null.");
AssertEreport(nargs >= 1 && nargs <= 3, MOD_PLSQL, "Args num is out of range.");

View File

@ -233,7 +233,8 @@ Boot_CreateStmt:
mapped_relation,
true,
REL_CMPRS_NOT_SUPPORT,
BOOTSTRAP_SUPERUSERID);
BOOTSTRAP_SUPERUSERID,
false);
ereport(DEBUG4, (errmsg("bootstrap relation created")));
/*

View File

@ -524,7 +524,7 @@ FdwRoutine* GetFdwRoutineByServerId(Oid serverid)
/* Get foreign-data wrapper OID for the server. */
tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid));
if (!HeapTupleIsValid(tp))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("cache lookup failed for foreign server %u", serverid)));
serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
fdwid = serverform->srvfdw;

301
src/gausskernel/cbb/utils/partition/partitionmap.cpp Executable file → Normal file
View File

@ -20,7 +20,7 @@
*
* IDENTIFICATION
* src/gausskernel/cbb/utils/partition/partitionmap.cpp
*
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
@ -379,33 +379,32 @@ static inline void constCompare(Const* value1, Const* value2, int& compare)
} \
} while (0)
#define buildRangeElement(range, type, typelen, relid, attrno, tuple, desc) \
do { \
Assert(PointerIsValid(range)); \
Assert(PointerIsValid(type) && PointerIsValid(attrno)); \
Assert(PointerIsValid(tuple) && PointerIsValid(desc)); \
Assert((attrno)->dim1 <= RANGE_PARTKEYMAXNUM); \
Assert((attrno)->dim1 == (typelen)); \
unserializePartitionStringAttribute((range)->boundary, \
RANGE_PARTKEYMAXNUM, \
(type), \
(typelen), \
(relid), \
(attrno), \
(tuple), \
Anum_pg_partition_boundaries, \
(desc)); \
(range)->partitionOid = HeapTupleGetOid(tuple); \
(range)->len = (typelen); \
#define BuildRangeElement(range, type, typelen, relid, attrno, tuple, desc, isInter) \
do { \
Assert(PointerIsValid(range)); \
Assert(PointerIsValid(type) && PointerIsValid(attrno)); \
Assert(PointerIsValid(tuple) && PointerIsValid(desc)); \
Assert((attrno)->dim1 <= RANGE_PARTKEYMAXNUM); \
Assert((attrno)->dim1 == (typelen)); \
unserializePartitionStringAttribute((range)->boundary, \
RANGE_PARTKEYMAXNUM, \
(type), \
(typelen), \
(relid), \
(attrno), \
(tuple), \
Anum_pg_partition_boundaries, \
(desc)); \
(range)->partitionOid = HeapTupleGetOid(tuple); \
(range)->len = (typelen); \
(range)->isInterval = (isInter); \
} while (0)
static void RebuildRangePartitionMap(RangePartitionMap* oldMap, RangePartitionMap* newMap);
static void RebuildIntervalPartitionMap(IntervalPartitionMap* oldMap, IntervalPartitionMap* newMap);
/* these routines are partition map related */
static void buildRangePartitionMap(Relation relation, Form_pg_partition partitioned_form, HeapTuple partitioned_tuple,
Relation pg_partition, List* partition_list);
Relation pg_partition, const List* partition_list);
static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int partkeyNum);
@ -635,7 +634,6 @@ void RelationInitPartitionMap(Relation relation)
}
partitioned_form = (Form_pg_partition)GETSTRUCT(partitioned_tuple);
/*
* For value based partition-table, we only have to retrieve partkeys
*/
@ -694,6 +692,7 @@ void RelationInitPartitionMap(Relation relation)
switch (partitioned_form->partstrategy) {
case PART_STRATEGY_RANGE:
case PART_STRATEGY_INTERVAL:
buildRangePartitionMap(relation, partitioned_form, partitioned_tuple, pg_partition, partition_list);
break;
default:
@ -765,11 +764,7 @@ void RebuildPartitonMap(PartitionMap* oldMap, PartitionMap* newMap)
// when the map is referenced, don't rebuild the partitionmap
if (oldMap->refcount == 0) {
if (PartitionMapIsRange(oldMap)) {
RebuildRangePartitionMap((RangePartitionMap*)oldMap, (RangePartitionMap*)newMap);
} else {
RebuildIntervalPartitionMap((IntervalPartitionMap*)oldMap, (IntervalPartitionMap*)newMap);
}
RebuildRangePartitionMap((RangePartitionMap*)oldMap, (RangePartitionMap*)newMap);
} else {
oldMap->isDirty = true;
elog(LOG, "map refcount is not zero when RebuildPartitonMap ");
@ -799,9 +794,6 @@ static void RebuildRangePartitionMap(RangePartitionMap* oldMap, RangePartitionMa
PARTITIONMAP_SWAPFIELD(Oid*, partitionKeyDataType);
}
static void RebuildIntervalPartitionMap(IntervalPartitionMap* oldMap, IntervalPartitionMap* newMap)
{}
/*
* copy the rangeElement
*/
@ -826,6 +818,79 @@ static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int pa
return ret;
}
RangeElement* CopyRangeElementsWithoutBoundary(const RangeElement* src, int elementNum)
{
Size size_ret = sizeof(RangeElement) * elementNum;
RangeElement* ret = (RangeElement*)palloc0(size_ret);
errno_t rc = memcpy_s(ret, size_ret, src, size_ret);
securec_check(rc, "\0", "\0");
return ret;
}
char* ReadIntervalStr(HeapTuple tuple, TupleDesc tupleDesc)
{
bool isNull = true;
Oid elemType;
int16 elemLen;
bool elemByval = false;
char elemAlign;
int numElems;
Datum* elemValues = NULL;
bool* elemNulls = NULL;
Datum attrRawValue = heap_getattr(tuple, (uint32)Anum_pg_partition_interval, tupleDesc, &isNull);
ArrayType* array = DatumGetArrayTypeP(attrRawValue);
elemType = ARR_ELEMTYPE(array);
Assert(elemType == TEXTOID);
get_typlenbyvalalign(elemType, &elemLen, &elemByval, &elemAlign);
deconstruct_array(array, elemType, elemLen, elemByval, elemAlign, &elemValues, &elemNulls, &numElems);
Assert(numElems == 1);
Assert(!elemNulls[0]);
char* intervalStr = text_to_cstring(DatumGetTextP(*elemValues));
pfree(elemValues);
pfree(elemNulls);
return intervalStr;
}
static Interval* ReadInterval(HeapTuple tuple, TupleDesc tupleDesc)
{
int32 typmod = -1;
char* intervalStr = ReadIntervalStr(tuple, tupleDesc);
Interval* res = char_to_interval(intervalStr, typmod);
pfree(intervalStr);
return res;
}
oidvector* ReadIntervalTablespace(HeapTuple tuple, TupleDesc tupleDesc)
{
Datum tablespaceRaw;
ArrayType* tablespaceArray = NULL;
bool isNull = false;
Oid* values = NULL;
int arraySize;
/* Get the raw data which contain interval tablespace's columns */
tablespaceRaw = heap_getattr(tuple, Anum_pg_partition_intablespace, tupleDesc, &isNull);
if (isNull) {
return NULL;
}
/* convert Datum to ArrayType */
tablespaceArray = DatumGetArrayTypeP(tablespaceRaw);
arraySize = ARR_DIMS(tablespaceArray)[0];
/* CHECK: the ArrayType of interval tablespace is valid */
if (ARR_NDIM(tablespaceArray) != 1 || arraySize <= 0 || ARR_HASNULL(tablespaceArray) ||
ARR_ELEMTYPE(tablespaceArray) != OIDOID) {
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("interval tablespace column's number is not a oid array")));
}
values = (Oid*)ARR_DATA_PTR(tablespaceArray);
return buildoidvector(values, arraySize);
}
/*
* @@GaussDB@@
* Target : data partition
@ -834,7 +899,7 @@ static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int pa
* Notes :
*/
static void buildRangePartitionMap(Relation relation, Form_pg_partition partitioned_form, HeapTuple partitioned_tuple,
Relation pg_partition, List* partition_list)
Relation pg_partition, const List* partition_list)
{
int range_itr = 0;
RangePartitionMap* range_map = NULL;
@ -870,6 +935,14 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio
partitionKeyDataType,
sizeof(Oid) * partitionKey->dim1);
securec_check(rc, "\0", "\0");
if (partitioned_form->partstrategy == PART_STRATEGY_INTERVAL) {
range_map->type.type = PART_TYPE_INTERVAL;
/* the interval partition only supports one partition key */
Assert(partitionKey->dim1 == 1);
range_map->intervalValue = ReadInterval(partitioned_tuple, RelationGetDescr(pg_partition));
range_map->intervalTablespace = ReadIntervalTablespace(partitioned_tuple, RelationGetDescr(pg_partition));
}
(void)MemoryContextSwitchTo(old_context);
/* allocate range element array */
@ -881,7 +954,8 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio
partition_tuple = (HeapTuple)lfirst(tuple_cell);
partition_form = (Form_pg_partition)GETSTRUCT(partition_tuple);
if (PART_STRATEGY_RANGE != partition_form->partstrategy) {
if (partition_form->partstrategy != PART_STRATEGY_RANGE &&
partition_form->partstrategy != PART_STRATEGY_INTERVAL) {
pfree_ext(range_eles);
pfree_ext(range_map);
@ -891,14 +965,14 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio
errdetail("Incorrect partition strategy for partition %u", HeapTupleGetOid(partition_tuple))));
}
buildRangeElement(&(range_eles[range_itr]),
BuildRangeElement(&(range_eles[range_itr]),
range_map->partitionKeyDataType,
range_map->partitionKey->dim1,
RelationGetRelid(relation),
range_map->partitionKey,
partition_tuple,
RelationGetDescr(pg_partition));
RelationGetDescr(pg_partition),
partition_form->partstrategy == PART_STRATEGY_INTERVAL);
range_itr++;
}
@ -1017,7 +1091,7 @@ Oid getRangePartitionOid(Relation relation, Const** partKeyValue, int32* partSeq
RangeElement* rangeElementIterator = NULL;
RangePartitionMap* rangePartMap = NULL;
Oid result = InvalidOid;
int keyNums = 0;
int keyNums;
int hit = -1;
int min_part_id = 0;
int max_part_id = 0;
@ -1084,13 +1158,39 @@ Oid getRangePartitionOid(Relation relation, Const** partKeyValue, int32* partSeq
return result;
}
/*
* return value: InvalidOid---when requested partition not created yet
*/
Oid getIntervalPartitionOid(IntervalPartitionMap* intervalPartMap, Const** partKeyValue, int32* partIndex,
PartitionArea* partArea, bool topClosed, bool missIsOk)
inline Const* CalcLowBoundary(const Const* upBoundary, Interval* intervalValue)
{
return InvalidOid;
Assert(upBoundary->consttype == TIMESTAMPOID || upBoundary->consttype == TIMESTAMPTZOID);
Timestamp lowTs = timestamp_mi_interval(DatumGetTimestamp(upBoundary->constvalue), intervalValue);
return makeConst(upBoundary->consttype,
upBoundary->consttypmod,
upBoundary->constcollid,
upBoundary->constlen,
TimestampGetDatum(lowTs),
upBoundary->constisnull,
upBoundary->constbyval);
}
inline int ValueCmpLowBoudary(Const** partKeyValue, const RangeElement* partition, Interval* intervalValue)
{
Assert(partition->isInterval);
Assert(partition->len == 1);
int compare = 0;
Const* lowBoundary = CalcLowBoundary(partition->boundary[0], intervalValue);
partitonKeyCompareForRouting(partKeyValue, &lowBoundary, partition->len, compare);
pfree(lowBoundary);
return compare;
}
/* the low boundary is close */
bool ValueSatisfyLowBoudary(Const** partKeyValue, RangeElement* partition, Interval* intervalValue, bool topClosed)
{
int compare = ValueCmpLowBoudary(partKeyValue, partition, intervalValue);
if (compare > 0 || (compare == 0 && topClosed)) {
return true;
}
return false;
}
/*
@ -1110,7 +1210,7 @@ int getNumberOfRangePartitions(Relation rel)
errmsg("CAN NOT get number of partition against NON-PARTITIONED relation")));
}
if (rel->partMap->type == PART_TYPE_RANGE) {
if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) {
RangePartitionMap* rangeMap = NULL;
rangeMap = (RangePartitionMap*)(rel->partMap);
@ -1121,33 +1221,9 @@ int getNumberOfRangePartitions(Relation rel)
return ret;
}
/*
* @@GaussDB@@
* Target : data partition
* Brief :
* Description :
* Notes :
*/
int getNumberOfIntervalPartitions(Relation rel)
{
return 0;
}
int getNumberOfPartitions(Relation rel)
{
int ranges = 0;
int intervals = 0;
if (!RELATION_IS_PARTITIONED(rel)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CAN NOT get number of partition against NON-PARTITIONED relation")));
}
ranges = getNumberOfRangePartitions(rel);
intervals = getNumberOfIntervalPartitions(rel);
return (ranges + intervals);
return getNumberOfRangePartitions(rel);
}
Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID)
@ -1164,9 +1240,7 @@ Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID)
return InvalidOid;
}
if (relation->partMap->type == PART_TYPE_RANGE) {
Assert(partID->partArea == PART_AREA_RANGE);
if (relation->partMap->type == PART_TYPE_RANGE || relation->partMap->type == PART_TYPE_INTERVAL) {
rang_map = (RangePartitionMap*)(relation->partMap);
if (partID->partSeq <= rang_map->rangeElementsNum) {
@ -1201,13 +1275,17 @@ PartitionIdentifier* partOidGetPartID(Relation rel, Oid partOid)
}
result = (PartitionIdentifier*)palloc0(sizeof(PartitionIdentifier));
if (PART_TYPE_RANGE == rel->partMap->type) {
if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) {
int i;
RangePartitionMap* rangeMap = (RangePartitionMap*)rel->partMap;
for (i = 0; i < rangeMap->rangeElementsNum; i++) {
if (partOid == rangeMap->rangeElements[i].partitionOid) {
result->partArea = PART_AREA_RANGE;
if (rangeMap->rangeElements[i].isInterval) {
result->partArea = PART_AREA_INTERVAL;
} else {
result->partArea = PART_AREA_RANGE;
}
result->partSeq = i;
result->fileExist = true;
result->partitionId = partOid;
@ -1237,9 +1315,7 @@ int partOidGetPartSequence(Relation rel, Oid partOid)
} else if (false == resultPartID->fileExist || PART_AREA_NONE == resultPartID->partArea) {
resultPartSequence = -1;
} else {
if (resultPartID->partArea == PART_AREA_RANGE) {
resultPartSequence = resultPartID->partSeq + 1;
}
resultPartSequence = resultPartID->partSeq + 1;
}
pfree_ext(resultPartID);
@ -1346,34 +1422,19 @@ void releasePartitionList(Relation relation, List** partList, LOCKMODE lockmode)
List* relationGetPartitionOidList(Relation rel)
{
List* result = NIL;
int conuter = 0;
int sumtotal = -1;
int rangeNumber = -1;
Bitmapset* mapset = NULL;
PartitionMap* map = NULL;
Oid partitionid = InvalidOid;
Oid partitionId = InvalidOid;
if (rel == NULL || rel->partMap == NULL) {
return NIL;
}
map = rel->partMap;
sumtotal = getPartitionNumber(map);
rangeNumber = ((RangePartitionMap*)map)->rangeElementsNum;
if (sumtotal > rangeNumber) {
mapset = bms_copy(((IntervalPartitionMap*)map)->sequenceMap);
PartitionMap* map = rel->partMap;
int sumTotal = getPartitionNumber(map);
for (int conuter = 0; conuter < sumTotal; ++conuter) {
partitionId = ((RangePartitionMap*)map)->rangeElements[conuter].partitionOid;
result = lappend_oid(result, partitionId);
}
for (conuter = 0; conuter < sumtotal; ++conuter) {
if (conuter < rangeNumber) { /* range partition */
partitionid = ((RangePartitionMap*)map)->rangeElements[conuter].partitionOid;
}
result = lappend_oid(result, partitionid);
}
bms_free_ext(mapset);
return result;
}
@ -1533,7 +1594,7 @@ int getPartitionNumber(PartitionMap* map)
{
int result = -1;
if (map->type == PART_TYPE_RANGE) {
if (map->type == PART_TYPE_RANGE || map->type == PART_TYPE_INTERVAL) {
result = ((RangePartitionMap*)map)->rangeElementsNum;
} else {
ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("unsupported partitioned strategy")));
@ -1708,3 +1769,45 @@ void decre_partmap_refcount(PartitionMap* map)
if (!IsBootstrapProcessingMode())
ResourceOwnerForgetPartitionMapRef(t_thrd.utils_cxt.CurrentResourceOwner, map);
}
/*
* Get the oid of the partition which is a interval partition and next to the droped range partition which is
* specificed by partOid. If the droped partition is a interval partition, the next partition no need to
* be changed to range partition, return InvalidOid. If the next partition is a range partition, nothing need
* to do, return InvalidOid.
*/
Oid GetNeedDegradToRangePartOid(Relation rel, Oid partOid)
{
/* never happen */
if (!PointerIsValid(rel) || !OidIsValid(partOid)) {
ereport(ERROR,
(errcode(ERRCODE_FETCH_DATA_FAILED), errmsg("invalid partitioned table relaiton or partition table oid")));
}
Assert(rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL);
/* In normal range partitioned tabel, there has no interval ranges. */
if (rel->partMap->type == PART_TYPE_RANGE) {
return InvalidOid;
}
RangePartitionMap* rangeMap = (RangePartitionMap*)rel->partMap;
for (int i = 0; i < rangeMap->rangeElementsNum; i++) {
if (rangeMap->rangeElements[i].partitionOid == partOid) {
/*
* 1. the droped range is interval range
* 2. there is no more ranges
* 3. the next partition is a range partition
*/
if (rangeMap->rangeElements[i].isInterval || (i == rangeMap->rangeElementsNum - 1) ||
!rangeMap->rangeElements[i + 1].isInterval) {
return InvalidOid;
}
return rangeMap->rangeElements[i + 1].partitionOid;
}
}
/* It must never happened. */
ereport(ERROR, (errcode(ERRCODE_CASE_NOT_FOUND), errmsg("Not find the target partiton %u", partOid)));
return InvalidOid;
}

View File

@ -34,6 +34,7 @@
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_hashbucket_fn.h"
#include "catalog/namespace.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
@ -234,7 +235,8 @@ static void get_sample_rows_for_query(
MemoryContext speccontext, Relation rel, VacuumStmt* vacstmt, int64* num_sample_rows, HeapTuple** samplerows);
template <bool isSingleColumn>
static void update_stats_catalog(
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats);
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats, int natts,
char relpersistence);
/* The sample info of special attribute for compute statistic for index or type of tsvector. */
typedef struct {
@ -494,6 +496,11 @@ static void analyze_rel_internal(Relation onerel, VacuumStmt* vacstmt, BufferAcc
return;
}
if (RELATION_IS_GLOBAL_TEMP(onerel) && !gtt_storage_attached(RelationGetRelid(onerel))) {
relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
/*
* We can ANALYZE any table except pg_statistic. See update_attstats
*/
@ -551,6 +558,8 @@ static void analyze_rel_internal(Relation onerel, VacuumStmt* vacstmt, BufferAcc
retValue = fdwroutine->AnalyzeForeignTable(onerel, &acquirefunc, &relpages, 0, false);
}
if (!retValue) {
/* Supress warning info for mysql_fdw */
messageLevel = isMysqlFDWFromTblOid(RelationGetRelid(onerel)) ? LOG : messageLevel;
ereport(messageLevel,
(errmsg(
"Skipping \"%s\" --- cannot analyze this foreign table.", RelationGetRelationName(onerel))));
@ -718,7 +727,7 @@ static int get_total_width(
total_width1 = 0;
for (i = 0; i < thisdata->attr_cnt; i++) {
for (unsigned int j = 0; j < vacattrstats[i]->num_attrs; ++j) {
for (unsigned int j = 0; j < thisdata->vacattrstats[i]->num_attrs; ++j) {
attr = thisdata->vacattrstats[i]->attrs[j];
/* This should match set_rel_width() in costsize.c */
@ -886,7 +895,8 @@ HeapTuple* get_total_rows(Relation onerel, VacuumStmt* vacstmt, BlockNumber relp
*numrows = acquirePartitionedSampleRows<estimate_table_rownum>(
onerel, vacstmt, elevel, rows, target_rows, totalrows, totaldeadrows, vacattrstats, attr_cnt);
} else if (isForeignTable ||
(onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(onerel)))) {
(onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE &&
(isMOTFromTblOid(RelationGetRelid(onerel)) || isOracleFDWFromTblOid(RelationGetRelid(onerel))))) {
/*
* @hdfs processing foreign table sampling operation
* get foreign table FDW routine
@ -1575,7 +1585,8 @@ static void do_analyze_rel(Relation onerel, VacuumStmt* vacstmt, BlockNumber rel
VacAttrStats* stats = vacattrstats[i];
if (stats->num_attrs > 1) {
stats->stats_valid = true;
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, 1, &stats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, 1, &stats,
RelationGetRelPersistence(onerel));
}
}
}
@ -4185,7 +4196,7 @@ void releaseSourceAfterDelteOrUpdateAttStats(
* function
*/
// Added parameter - char relkind by data partition
void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats)
void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats** vacattrstats, char relpersistence)
{
Relation pgstat = NULL;
Relation pgstat_ext = NULL;
@ -4223,7 +4234,7 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
}
/* do multi column stats update */
update_stats_catalog<false>(pgstat_ext, oldcontext, relid, relkind, inh, stats);
update_stats_catalog<false>(pgstat_ext, oldcontext, relid, relkind, inh, stats, natts, relpersistence);
} else {
/* Open rel handler for pg_statistic to process single-column statistic */
if (!pgstat) {
@ -4231,7 +4242,7 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
}
/* do signle column stats update */
update_stats_catalog<true>(pgstat, oldcontext, relid, relkind, inh, stats);
update_stats_catalog<true>(pgstat, oldcontext, relid, relkind, inh, stats, natts, relpersistence);
}
}
@ -4258,7 +4269,8 @@ void update_attstats(Oid relid, char relkind, bool inh, int natts, VacAttrStats*
*/
template <bool isSingleColumn>
static void update_stats_catalog(
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats)
Relation pgstat, MemoryContext oldcontext, Oid relid, char relkind, bool inh, VacAttrStats* stats, int natts,
char relpersistence)
{
HeapTuple stup, oldtup;
int i, k, n;
@ -4399,6 +4411,17 @@ static void update_stats_catalog(
values[Anum_pg_statistic_ext_stakey - 1] = PointerGetDatum(stakey);
}
/* Update column statistic to localhash, not catalog */
if (relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
up_gtt_att_statistic(relid,
attnum,
natts,
RelationGetDescr(pgstat),
values,
nulls);
return;
}
/* store tuple to pg_statistic(_ext) */
PG_TRY();
{
@ -6543,11 +6566,13 @@ static bool do_analyze_samplerows(Relation onerel, VacuumStmt* vacstmt, int attr
* previous statistics for the target columns. (If there are stats in
* pg_statistic for columns we didn't process, we leave them alone.)
*/
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats,
RelationGetRelPersistence(onerel));
for (i = 0; i < nindexes; i++) {
AnlIndexData* thisdata = &indexdata[i];
update_attstats(RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats);
update_attstats(RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats,
RelationGetRelPersistence(Irel[i]));
}
return true;
@ -6682,7 +6707,8 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
* previous statistics for the target columns. (If there are stats in
* pg_statistic for columns we didn't process, we leave them alone.)
*/
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, inh, attr_cnt, vacattrstats,
RelationGetRelPersistence(onerel));
/*
* Update stats of dfs table or delta table using statistic of complex table
@ -6690,10 +6716,12 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
*/
if (analyzemode == ANALYZECOMPLEX) {
if (!vacstmt->pstGlobalStatEx[ANALYZEMAIN - 1].exec_query)
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, false, attr_cnt, vacattrstats);
update_attstats(RelationGetRelid(onerel), STARELKIND_CLASS, false,
attr_cnt, vacattrstats, RelationGetRelPersistence(onerel));
if (!vacstmt->pstGlobalStatEx[ANALYZEDELTA - 1].exec_query)
update_attstats(onerel->rd_rel->reldeltarelid, STARELKIND_CLASS, false, attr_cnt, vacattrstats);
update_attstats(onerel->rd_rel->reldeltarelid, STARELKIND_CLASS, false,
attr_cnt, vacattrstats, RelationGetRelPersistence(onerel));
}
/*
@ -6709,7 +6737,8 @@ static void do_analyze_sampletable(Relation onerel, VacuumStmt* vacstmt, int att
AnlIndexData* thisdata = &indexdata[i];
update_attstats(
RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats);
RelationGetRelid(Irel[i]), STARELKIND_CLASS, false, thisdata->attr_cnt, thisdata->vacattrstats,
RelationGetRelPersistence(Irel[i]));
}
}

View File

@ -33,6 +33,7 @@
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/tablecmds.h"
#include "commands/vacuum.h"
@ -141,6 +142,9 @@ static Datum pgxc_parallel_execution(const char* query, ExecNodes* exec_nodes);
static int switch_relfilenode_execnode(Oid relOid1, Oid relOid2, bool isbucket, RedisSwitchNode* rsn);
#endif
static void swapRelationIndicesRelfileNode(Relation rel1, Relation rel2, bool swapBucket);
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables);
/* ---------------------------------------------------------------------------
* This cluster code allows for clustering multiple tables at once. Because
* of this, we cannot just run everything on a single transaction, or we
@ -453,6 +457,12 @@ void cluster_rel(Oid tableOid, Oid partitionOid, Oid indexOid, bool recheck, boo
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot vacuum temporary tables of other sessions")));
}
if (RELATION_IS_GLOBAL_TEMP(OldHeap) && !gtt_storage_attached(RelationGetRelid(OldHeap))) {
relation_close(OldHeap, lockMode);
gstrace_exit(GS_TRC_ID_cluster_rel);
return;
}
/*
* Also check for active uses of the relation in the current transaction,
* including open scans and pending AFTER trigger events.
@ -688,6 +698,7 @@ static void rebuild_relation(
Oid tableOid = RelationGetRelid(OldHeap);
Oid tableSpace = OldHeap->rd_rel->reltablespace;
Oid OIDNewHeap;
char relpersistence;
bool is_system_catalog = false;
bool swap_toast_by_content = false;
TransactionId frozenXid;
@ -699,6 +710,7 @@ static void rebuild_relation(
mark_index_clustered(OldHeap, indexOid);
/* Remember if it's a system catalog */
relpersistence = OldHeap->rd_rel->relpersistence;
is_system_catalog = IsSystemRelation(OldHeap);
/* Close relcache entry, but keep lock until transaction commit */
@ -732,7 +744,8 @@ static void rebuild_relation(
* Swap the physical files of the target and transient tables, then
* rebuild the target's indexes and throw away the transient table.
*/
finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage);
finish_heap_swap(
tableOid, OIDNewHeap, is_system_catalog, swap_toast_by_content, false, frozenXid, memUsage, relpersistence);
/* report vacuum full stat to PgStatCollector */
pgstat_report_vacuum(tableOid, InvalidOid, is_shared, deleteTupleNum);
@ -1783,6 +1796,8 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
TransactionId FreezeXid;
bool use_sort = false;
double tups_vacuumed = 0;
bool isGtt = false;
TransactionId gttRelfrozenxid = 0;
/*
* Open the relations we need.
@ -1794,6 +1809,10 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
else
OldIndex = NULL;
if (RELATION_IS_GLOBAL_TEMP(OldHeap)) {
isGtt = true;
}
/*
* If the OldHeap has a toast table, get lock on the toast table to keep
* it from being vacuumed. This is needed because autovacuum processes
@ -1851,32 +1870,38 @@ static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, int
* FreezeXid will become the table's new relfrozenxid, and that mustn't go
* backwards, so take the max.
*/
bool isNull = false;
TransactionId relfrozenxid;
Relation rel = heap_open(RelationRelationId, AccessShareLock);
HeapTuple tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("cache lookup failed for relation %u", RelationGetRelid(OldHeap))));
}
Datum xid64datum = heap_getattr(tuple, Anum_pg_class_relfrozenxid64, RelationGetDescr(rel), &isNull);
heap_close(rel, AccessShareLock);
heap_freetuple(tuple);
if (isNull) {
relfrozenxid = OldHeap->rd_rel->relfrozenxid;
if (TransactionIdPrecedes(t_thrd.xact_cxt.ShmemVariableCache->nextXid, relfrozenxid) ||
!TransactionIdIsNormal(relfrozenxid)) {
relfrozenxid = FirstNormalTransactionId;
}
if (isGtt) {
(void)get_gtt_relstats(OIDOldHeap, NULL, NULL, NULL, &gttRelfrozenxid);
if (TransactionIdIsValid(gttRelfrozenxid) && TransactionIdPrecedes(FreezeXid, gttRelfrozenxid))
FreezeXid = gttRelfrozenxid;
} else {
relfrozenxid = DatumGetTransactionId(xid64datum);
}
bool isNull = false;
TransactionId relfrozenxid;
Relation rel = heap_open(RelationRelationId, AccessShareLock);
HeapTuple tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(OIDOldHeap));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("cache lookup failed for relation %u", RelationGetRelid(OldHeap))));
}
Datum xid64datum = heap_getattr(tuple, Anum_pg_class_relfrozenxid64, RelationGetDescr(rel), &isNull);
heap_close(rel, AccessShareLock);
heap_freetuple(tuple);
if (TransactionIdPrecedes(FreezeXid, relfrozenxid)) {
FreezeXid = relfrozenxid;
if (isNull) {
relfrozenxid = OldHeap->rd_rel->relfrozenxid;
if (TransactionIdPrecedes(t_thrd.xact_cxt.ShmemVariableCache->nextXid, relfrozenxid) ||
!TransactionIdIsNormal(relfrozenxid)) {
relfrozenxid = FirstNormalTransactionId;
}
} else {
relfrozenxid = DatumGetTransactionId(xid64datum);
}
if (TransactionIdPrecedes(FreezeXid, relfrozenxid)) {
FreezeXid = relfrozenxid;
}
}
/* return selected value to caller */
*pFreezeXid = FreezeXid;
@ -2765,7 +2790,7 @@ static void SwapCStoreTables(Oid relId1, Oid relId2, Oid parentOid, Oid tempTabl
* cleaning up (including rebuilding all indexes on the old heap).
*/
void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bool swap_toast_by_content,
bool check_constraints, TransactionId frozenXid, AdaptMem* memInfo)
bool checkConstraints, TransactionId frozenXid, AdaptMem* memInfo, char newrelpersistence)
{
ObjectAddress object;
Oid mapped_tables[4];
@ -2781,8 +2806,15 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo
* Swap the contents of the heap relations (including any toast tables).
* Also set old heap's relfrozenxid to frozenXid.
*/
swap_relation_files(
OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId), swap_toast_by_content, frozenXid, mapped_tables);
if (newrelpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
Assert(!is_system_catalog);
GttSwapRelationFiles(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
} else {
swap_relation_files(OIDOldHeap, OIDNewHeap, (OIDOldHeap == RelationRelationId),
swap_toast_by_content, frozenXid, mapped_tables);
}
/*
* If it's a system catalog, queue an sinval message to flush all
* catcaches on the catalog when we reach CommandCounterIncrement.
@ -2806,7 +2838,7 @@ void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, bo
* broken ones, so it can't be necessary to set indcheckxmin.
*/
reindex_flags = REINDEX_REL_SUPPRESS_INDEX_USE;
if (check_constraints)
if (checkConstraints)
reindex_flags |= REINDEX_REL_CHECK_CONSTRAINTS;
reindex_relation(OIDOldHeap, reindex_flags, REINDEX_ALL_INDEX, memInfo);
@ -2965,6 +2997,111 @@ static List* get_tables_to_cluster(MemoryContext cluster_context)
return rvs;
}
static void GttSwapRelationFiles(Oid r1, Oid r2, bool targetIsPgClass, bool swapToastByContent,
TransactionId frozenXid, Oid *mappedTables)
{
Relation relRelation;
Oid relfilenode1,
relfilenode2;
Relation rel1;
Relation rel2;
relRelation = relation_open(RelationRelationId, RowExclusiveLock);
rel1 = relation_open(r1, AccessExclusiveLock);
rel2 = relation_open(r2, AccessExclusiveLock);
relfilenode1 = gtt_fetch_current_relfilenode(r1);
relfilenode2 = gtt_fetch_current_relfilenode(r2);
Assert(OidIsValid(relfilenode1) && OidIsValid(relfilenode2));
gtt_switch_rel_relfilenode(r1, relfilenode1, r2, relfilenode2, true);
CacheInvalidateRelcache(rel1);
CacheInvalidateRelcache(rel2);
if (rel1->rd_rel->reltoastrelid || rel2->rd_rel->reltoastrelid) {
if (swapToastByContent) {
if (rel1->rd_rel->reltoastrelid && rel2->rd_rel->reltoastrelid) {
GttSwapRelationFiles(rel1->rd_rel->reltoastrelid,
rel2->rd_rel->reltoastrelid,
targetIsPgClass,
swapToastByContent,
frozenXid,
mappedTables);
} else {
elog(ERROR, "cannot swap toast files by content when there's only one");
}
} else {
ObjectAddress baseobject,
toastobject;
long count;
if (IsSystemRelation(rel1)) {
elog(ERROR, "cannot swap toast files by links for system catalogs");
}
if (rel1->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel1->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
if (rel2->rd_rel->reltoastrelid) {
count = deleteDependencyRecordsFor(RelationRelationId,
rel2->rd_rel->reltoastrelid,
false);
if (count != 1) {
elog(ERROR, "expected one dependency record for TOAST table, found %ld",
count);
}
}
/* Register new dependencies */
baseobject.classId = RelationRelationId;
baseobject.objectSubId = 0;
toastobject.classId = RelationRelationId;
toastobject.objectSubId = 0;
if (rel1->rd_rel->reltoastrelid) {
baseobject.objectId = r1;
toastobject.objectId = rel1->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject,
DEPENDENCY_INTERNAL);
}
if (rel2->rd_rel->reltoastrelid) {
baseobject.objectId = r2;
toastobject.objectId = rel2->rd_rel->reltoastrelid;
recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
}
}
}
if (swapToastByContent && rel1->rd_rel->relkind == RELKIND_TOASTVALUE &&
rel2->rd_rel->relkind == RELKIND_TOASTVALUE) {
GttSwapRelationFiles(rel1->rd_rel->reltoastidxid,
rel2->rd_rel->reltoastidxid,
targetIsPgClass,
swapToastByContent,
InvalidTransactionId,
mappedTables);
}
relation_close(rel1, NoLock);
relation_close(rel2, NoLock);
relation_close(relRelation, RowExclusiveLock);
RelationCloseSmgrByOid(r1);
RelationCloseSmgrByOid(r2);
CommandCounterIncrement();
}
/*
* Reconstruct and rewrite the given tuple
*

View File

@ -34,6 +34,7 @@
#ifdef PGXC
#include "catalog/pg_trigger.h"
#endif
#include "catalog/storage_gtt.h"
#include "commands/copy.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
@ -982,7 +983,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
Assert(rel);
/* check read-only transaction */
if (u_sess->attr.attr_common.XactReadOnly && !RelationIsLocalTemp(rel))
if (u_sess->attr.attr_common.XactReadOnly && !RELATION_IS_TEMP(rel))
PreventCommandIfReadOnly("COPY FROM");
/* set write for backend status for the thread, we will use it to check default transaction readOnly */
@ -3479,6 +3480,7 @@ static uint64 CopyFrom(CopyState cstate)
0);
ExecOpenIndices(resultRelInfo);
init_gtt_storage(CMD_INSERT, resultRelInfo);
resultRelationDesc = resultRelInfo->ri_RelationDesc;
isPartitionRel = RELATION_IS_PARTITIONED(resultRelationDesc);

View File

@ -90,7 +90,7 @@ void RemoveObjects(DropStmt* stmt, bool missing_ok, bool is_securityadmin)
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", funcOid)));
if (((Form_pg_proc)GETSTRUCT(tup))->proisagg)
if (PROC_IS_AGG(((Form_pg_proc)GETSTRUCT(tup))->prokind))
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", NameListToString(objname)),
errhint("Use DROP AGGREGATE to drop aggregate functions.")));

View File

@ -1024,8 +1024,7 @@ void CreateFunction(CreateFunctionStmt* stmt, const char* queryString)
languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
false, /* not an aggregate */
isWindowFunc,
stmt->isProcedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
security,
isLeakProof,
isStrict,
@ -1181,7 +1180,7 @@ void RemoveFunctionById(Oid funcOid)
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", funcOid)));
Form_pg_proc procedureStruct = (Form_pg_proc)GETSTRUCT(tup);
isagg = procedureStruct->proisagg;
isagg = PROC_IS_AGG(procedureStruct->prokind);
if (procedureStruct->prolang == ClanguageId) {
PrepareCFunctionLibrary(tup);
@ -1245,7 +1244,7 @@ void RenameFunction(List* name, List* argtypes, const char* newname)
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", procOid)));
procForm = (Form_pg_proc)GETSTRUCT(tup);
if (procForm->proisagg)
if (PROC_IS_AGG(procForm->prokind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", NameListToString(name)),
@ -1308,7 +1307,7 @@ void AlterFunctionOwner(List* name, List* argtypes, Oid newOwnerId)
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", procOid)));
if (((Form_pg_proc)GETSTRUCT(tup))->proisagg)
if (PROC_IS_AGG(((Form_pg_proc)GETSTRUCT(tup))->prokind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", NameListToString(name)),
@ -1507,7 +1506,7 @@ void AlterFunction(AlterFunctionStmt* stmt)
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->func->funcname));
if (procForm->proisagg)
if (PROC_IS_AGG(procForm->prokind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", NameListToString(stmt->func->funcname))));
@ -1821,11 +1820,11 @@ void CreateCast(CreateCastStmt* stmt)
if (procstruct->provolatile == PROVOLATILE_VOLATILE)
ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must not be volatile")));
#endif
if (procstruct->proisagg)
if (PROC_IS_AGG(procstruct->prokind))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be an aggregate function")));
if (procstruct->proiswindow)
if (PROC_IS_WIN(procstruct->prokind))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must not be a window function")));
if (procstruct->proretset)

View File

@ -332,6 +332,23 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
List* partitionTableList = NIL;
List* partitionIndexdef = NIL;
List* partitiontspList = NIL;
char relPersistence;
bool concurrent;
/*
* Force non-concurrent build on temporary relations, even if CONCURRENTLY
* was requested. Other backends can't access a temporary relation, so
* there's no harm in grabbing a stronger lock, and a non-concurrent DROP
* is more efficient. Do this before any use of the concurrent option is
* done.
*/
relPersistence = get_rel_persistence(relationId);
if (stmt->concurrent && !(relPersistence == RELPERSISTENCE_TEMP ||
relPersistence == RELPERSISTENCE_GLOBAL_TEMP)) {
concurrent = true;
} else {
concurrent = false;
}
/*
* count attributes in index
@ -356,7 +373,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
* the relation. To avoid lock upgrade hazards, that lock should be at
* least as strong as the one we take here.
*/
lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
rel = heap_open(relationId, lockmode);
relationId = RelationGetRelid(rel);
@ -393,7 +410,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
/*
* partitioned index not is not support concurrent index
*/
if (stmt->isPartitioned && stmt->concurrent) {
if (stmt->isPartitioned && concurrent) {
ereport(
ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot create concurrent partitioned indexes ")));
}
@ -655,8 +672,8 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
indexInfo->ii_ExclusionStrats = NULL;
indexInfo->ii_Unique = stmt->unique;
/* In a concurrent build, mark it not-ready-for-inserts */
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_ReadyForInserts = !concurrent;
indexInfo->ii_Concurrent = concurrent;
indexInfo->ii_BrokenHotChain = false;
indexInfo->ii_PgClassAttrId = 0;
@ -765,7 +782,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
* A valid stmt->oldPSortOid implies that we already have a built form
* of the psort index.
*/
if ((OidIsValid(stmt->oldNode) && !(skip_build && !stmt->concurrent) &&
if ((OidIsValid(stmt->oldNode) && !(skip_build && !concurrent) &&
!u_sess->attr.attr_sql.enable_cluster_resize) ||
(OidIsValid(stmt->oldPSortOid) && !OidIsValid(stmt->oldNode))) {
ereport(defence_errlevel(),
@ -803,7 +820,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
stmt->initdeferred,
g_instance.attr.attr_common.allowSystemTableMods,
true,
stmt->concurrent,
concurrent,
&extra);
heap_close(rel, NoLock);
return indexRelationId;
@ -855,8 +872,8 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
stmt->deferrable,
stmt->initdeferred,
(g_instance.attr.attr_common.allowSystemTableMods || u_sess->attr.attr_common.IsInplaceUpgrade),
skip_build || stmt->concurrent,
stmt->concurrent,
skip_build || concurrent,
concurrent,
&extra);
/* Add any requested comment */
if (stmt->idxcomment != NULL)
@ -984,12 +1001,19 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
return indexRelationId;
}
if (!stmt->concurrent) {
if (!concurrent) {
/* Close the heap and we're done, in the non-concurrent case */
heap_close(rel, NoLock);
return indexRelationId;
}
// cstore relation doesn't support concurrent INDEX now.
if (OidIsValid(rel->rd_rel->relcudescrelid)) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("column store table does not support concurrent INDEX yet"),
errdetail("The feature is not currently supported")));
}
/* save lockrelid and locktag for below, then close rel */
heaprelid = rel->rd_lockInfo.lockRelId;
SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
@ -2105,6 +2129,8 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
Oid heapOid = InvalidOid;
Oid heapPartOid = InvalidOid;
LOCKMODE lockmode;
Relation irel;
char persistence;
/* lock level used here should match index lock reindex_index() */
if (partition_name != NULL)
@ -2120,6 +2146,13 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
false,
RangeVarCallbackForReindexIndex,
(void*)&heapOid);
/*
* Obtain the current persistence of the existing index. We already hold
* lock on the index.
*/
irel = index_open(indOid, NoLock);
persistence = irel->rd_rel->relpersistence;
index_close(irel, NoLock);
if (partition_name != NULL)
indPartOid = partitionNameGetPartitionOid(indOid,
@ -2131,7 +2164,7 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
PartitionNameCallbackForIndexPartition,
(void*)&heapPartOid,
ShareLock); // lock on heap partition
reindex_index(indOid, indPartOid, false, mem_info, false);
reindex_index(indOid, indPartOid, false, mem_info, false, persistence);
}
void PartitionNameCallbackForIndexPartition(Oid partitionedRelationOid, const char* partitionName, Oid partId,

View File

@ -130,8 +130,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
F_FMGR_C_VALIDATOR,
pltemplate->tmplhandler,
pltemplate->tmpllibrary,
false, /* isAgg */
false, /* isWindowFunc */
PROKIND_FUNCTION, /* prokind */
false, /* security_definer */
false, /* isLeakProof */
false, /* isStrict */
@ -174,8 +173,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
F_FMGR_C_VALIDATOR,
pltemplate->tmplinline,
pltemplate->tmpllibrary,
false, /* isAgg */
false, /* isWindowFunc */
PROKIND_FUNCTION, /* prokind */
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */
@ -220,8 +218,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
F_FMGR_C_VALIDATOR,
pltemplate->tmplvalidator,
pltemplate->tmpllibrary,
false, /* isAgg */
false, /* isWindowFunc */
PROKIND_FUNCTION, /* prokind */
false, /* security_definer */
false, /* isLeakProof */
true, /* isStrict */

View File

@ -408,7 +408,8 @@ void DefineSequence(CreateSeqStmt* seq)
isUseLocalSeq = IS_SINGLE_NODE || isTempNamespace(namespaceOid);
bool notSupportTmpSeq = false;
if (seq->sequence->relpersistence == RELPERSISTENCE_TEMP) {
if (seq->sequence->relpersistence == RELPERSISTENCE_TEMP ||
seq->sequence->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
notSupportTmpSeq = true;
} else if (IS_MAIN_COORDINATOR || IS_SINGLE_NODE) {
if (seq->canCreateTempSeq) {

View File

@ -39,14 +39,12 @@ void DoShutdown(ShutdownStmt* stmt)
if (shutdown_mode == NULL || strcmp(shutdown_mode, "fast") == 0) {
/* default value is SIGINT, need to do nothing. */
} else if (strcmp(shutdown_mode, "smart") == 0) {
signal = SIGTERM;
} else if (strcmp(shutdown_mode, "immediate") == 0) {
signal = SIGQUIT;
} else {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unknow parameter: %s\nshutdown only support fast, smart and immediate mode.\n", shutdown_mode)));
errmsg("unknow parameter: %s\nshutdown only support fast and immediate mode.\n", shutdown_mode)));
}
if (gs_signal_send(PostmasterPid, signal)) {

View File

@ -61,6 +61,7 @@
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "catalog/cstore_ctlg.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
@ -522,18 +523,19 @@ static void RangeVarCallbackForAlterRelation(
const RangeVar* rv, Oid relid, Oid oldrelid, bool target_is_partition, void* arg);
static bool CheckRangePartitionKeyType(Oid typoid);
static void CheckRangePartitionKeyType(Form_pg_attribute* attrs, List* pos);
static void CheckIntervalPartitionKeyType(Form_pg_attribute* attrs, List* pos);
static void CheckPartitionTablespace(const char* spcname, Oid owner);
static void ComparePartitionValue(List* pos, Form_pg_attribute* attrs, PartitionState* partTableState);
static bool ConfirmTypeInfo(Oid* target_oid, int* target_mod, Const* src, Form_pg_attribute attrs, bool isinterval);
static void addToastTableForNewPartition(Relation relation, Oid newPartId);
void addToastTableForNewPartition(Relation relation, Oid newPartId);
static void ATPrepAddPartition(Relation rel);
static void ATPrepDropPartition(Relation rel);
static void ATPrepUnusableIndexPartition(Relation rel);
static void ATPrepUnusableAllIndexOnPartition(Relation rel);
static void ATExecAddPartition(Relation rel, AddPartitionState* partState);
static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd);
void fastDropPartition(Relation rel, Oid partOid, const char* stmt);
static void ATExecUnusableIndexPartition(Relation rel, const char* partition_name);
static void ATExecUnusableIndex(Relation rel);
static void ATExecUnusableAllIndexOnPartition(Relation rel, const char* partition_name);
@ -607,6 +609,8 @@ static void ResetRelRedisCtidRelOptions(
Relation rel, Oid part_oid, int cat_id, int att_num, int att_inx, Oid pgcat_oid);
static bool WLMRelationCanTruncate(Relation rel);
static void alter_partition_policy_if_needed(Relation rel, List* defList);
static OnCommitAction GttOncommitOption(const List *options);
/* get all partitions oid */
static List* get_all_part_oid(Oid relid)
@ -676,6 +680,13 @@ static void CheckCStoreUnsupportedFeature(CreateStmt* stmt)
errdetail("cstore/timeseries don't support relation defination with inheritance.")));
}
if (stmt->partTableState && stmt->partTableState->intervalPartDef) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Unsupport feature"),
errdetail("cstore/timeseries don't support interval partition type.")));
}
/* Check constraints */
ListCell* lc = NULL;
foreach (lc, stmt->tableEltsDup) {
@ -1428,12 +1439,16 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
stmt->relation->relpersistence = RELPERSISTENCE_PERMANENT;
/* Check consistency of arguments */
if (stmt->oncommit != ONCOMMIT_NOOP && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
if (stmt->oncommit != ONCOMMIT_NOOP &&
!(stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables")));
/* @Temp Table. We do not support on commit drop right now. */
if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP && stmt->oncommit == ONCOMMIT_DROP)
if ((stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) &&
stmt->oncommit == ONCOMMIT_DROP)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT only support PRESERVE ROWS or DELETE ROWS option")));
@ -1493,7 +1508,9 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
* code. This is needed because calling code might not expect untrusted
* tables to appear in pg_temp at the front of its search path.
*/
if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP && InSecurityRestrictedOperation())
if ((stmt->relation->relpersistence == RELPERSISTENCE_TEMP ||
stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) &&
InSecurityRestrictedOperation())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("cannot create temporary table within security-restricted operation")));
@ -1566,6 +1583,41 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
/*
* Parse and validate reloptions, if any.
*/
/* global temp table */
OnCommitAction oncommitAction = GttOncommitOption(stmt->options);
if (stmt->relation->relpersistence == RELPERSISTENCE_GLOBAL_TEMP &&
relkind == RELKIND_RELATION) {
if (oncommitAction != ONCOMMIT_NOOP) {
if (stmt->oncommit != ONCOMMIT_NOOP && stmt->oncommit != oncommitAction) {
elog(ERROR, "could not create global temporary table with different on commit parameter and with "
"clause options at same time");
}
stmt->oncommit = oncommitAction;
} else {
DefElem *opt = makeNode(DefElem);
opt->type = T_DefElem;
opt->defnamespace = NULL;
opt->defname = "on_commit_delete_rows";
opt->defaction = DEFELEM_UNSPEC;
/* use reloptions to remember on commit clause */
if (stmt->oncommit == ONCOMMIT_DELETE_ROWS) {
opt->arg = reinterpret_cast<Node *>(makeString("true"));
} else if (stmt->oncommit == ONCOMMIT_PRESERVE_ROWS) {
opt->arg = reinterpret_cast<Node *>(makeString("false"));
} else if (stmt->oncommit == ONCOMMIT_NOOP) {
opt->arg = reinterpret_cast<Node *>(makeString("false"));
} else {
elog(ERROR, "global temp table not support on commit drop clause");
}
stmt->options = lappend(stmt->options, opt);
}
} else if (oncommitAction != ONCOMMIT_NOOP) {
elog(ERROR, "The parameter on_commit_delete_rows is exclusive to the global temp table, which cannot be "
"specified by a regular table");
}
reloptions = transformRelOptions((Datum)0, stmt->options, NULL, validnsps, true, false);
orientedFrom = (Node*)makeString(ORIENTATION_ROW); /* default is ORIENTATION_ROW */
@ -1722,16 +1774,18 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
if (stmt->partTableState) {
List* pos = NIL;
bool is_interval = false;
/* get partitionkey's position */
pos = GetPartitionkeyPos(stmt->partTableState->partitionKey, schema);
/* check partitionkey's datatype */
if (stmt->partTableState->partitionStrategy == PART_STRATEGY_VALUE)
if (stmt->partTableState->partitionStrategy == PART_STRATEGY_VALUE) {
CheckValuePartitionKeyType(descriptor->attrs, pos);
else
CheckPartitionKeyType(descriptor->attrs, pos, is_interval);
} else if (stmt->partTableState->partitionStrategy == PART_STRATEGY_INTERVAL) {
CheckIntervalPartitionKeyType(descriptor->attrs, pos);
} else {
CheckRangePartitionKeyType(descriptor->attrs, pos);
}
/*
* Check partitionkey's value for none value-partition table as for value
@ -1799,14 +1853,12 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
if (colDef->raw_default != NULL) {
RawColumnDefault* rawEnt = NULL;
if (relkind == RELKIND_FOREIGN_TABLE) {
if (!(IsA(stmt, CreateForeignTableStmt) &&
isMOTTableFromSrvName(((CreateForeignTableStmt*)stmt)->servername)))
ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("default values on foreign tables are not supported")));
}
Assert(colDef->cooked_default == NULL);
rawEnt = (RawColumnDefault*)palloc(sizeof(RawColumnDefault));
rawEnt->attnum = attnum;
@ -1847,7 +1899,7 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId)
Assert((createbucket == true && bucketinfo->bucketlist != NULL && bucketinfo->bucketcol != NULL) ||
(createbucket == false && bucketinfo->bucketlist == NULL && bucketinfo->bucketcol != NULL));
}
} else {
} else {
/* here is normal mode */
/* check if the table can be hash partition */
if (!IS_SINGLE_NODE && !IsInitdb && (relkind == RELKIND_RELATION) && !IsSystemNamespace(namespaceId) &&
@ -2342,10 +2394,10 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec
LOCKMODE lockmode = AccessExclusiveLock;
bool cn_miss_relation = false;
StringInfo relation_namelist = makeStringInfo();
char relPersistence;
/* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
if (drop->concurrent) {
flags |= PERFORM_DELETION_CONCURRENTLY;
lockmode = ShareUpdateExclusiveLock;
Assert(drop->removeType == OBJECT_INDEX);
if (list_length(drop->objects) != 1)
@ -2461,10 +2513,23 @@ void RemoveRelations(DropStmt* drop, StringInfo tmp_queryString, RemoteQueryExec
errmsg("%s is redistributing, please retry later.", delrel->rd_rel->relname.data)));
}
// cstore relation doesn't support concurrent INDEX now.
if (drop->concurrent == true && delrel != NULL && OidIsValid(delrel->rd_rel->relcudescrelid)) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("column store table does not support concurrent INDEX yet"),
errdetail("The feature is not currently supported")));
}
if (delrel != NULL) {
relation_close(delrel, NoLock);
}
relPersistence = get_rel_persistence(relOid);
if (drop->concurrent &&
!(relPersistence == RELPERSISTENCE_TEMP || relPersistence == RELPERSISTENCE_GLOBAL_TEMP)) {
Assert(list_length(drop->objects) == 1 && drop->removeType == OBJECT_INDEX);
flags |= PERFORM_DELETION_CONCURRENTLY;
}
/* OK, we're ready to delete this one */
obj.classId = RelationRelationId;
obj.objectId = relOid;
@ -2579,7 +2644,7 @@ ObjectAddresses* PreCheckforRemoveObjects(
(errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", funcOid)));
}
if (((Form_pg_proc)GETSTRUCT(tup))->proisagg)
if (PROC_IS_AGG(((Form_pg_proc)GETSTRUCT(tup))->prokind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function", NameListToString(objname)),
@ -3051,6 +3116,10 @@ void ExecuteTruncate(TruncateStmt* stmt)
*/
CheckTableForSerializableConflictIn(rel);
if (RELATION_IS_GLOBAL_TEMP(rel) && !gtt_storage_attached(RelationGetRelid(rel))) {
continue;
}
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE && isMOTFromTblOid(RelationGetRelid(rel))) {
FdwRoutine* fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(rel));
if (fdwroutine->TruncateForeignTable != NULL) {
@ -4551,7 +4620,6 @@ void RenameRelationInternal(Oid myrelid, const char* newrelname)
*/
if (targetrelation->rd_rel->relkind == RELKIND_INDEX) {
Oid constraintId = get_index_constraint(myrelid);
if (OidIsValid(constraintId))
RenameConstraintById(constraintId, newrelname);
}
@ -5272,6 +5340,17 @@ void AlterTable(Oid relid, LOCKMODE lockmode, AlterTableStmt* stmt)
/* Caller is required to provide an adequate lock. */
rel = relation_open(relid, lockmode);
/* We allow to alter global temp table only this session use it */
if (RELATION_IS_GLOBAL_TEMP(rel)) {
if (is_other_backend_use_gtt(RelationGetRelid(rel))) {
ereport(
ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can not alter table %s when other backend attached this global temp table",
RelationGetRelationName(rel))));
}
}
CheckTableNotInUse(rel, "ALTER TABLE");
/*
@ -6595,6 +6674,28 @@ static void ATRewriteTables(List** wqueue, LOCKMODE lockmode)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot rewrite temporary tables of other sessions")));
if (RELATION_IS_GLOBAL_TEMP(OldHeap)) {
/* gtt may not attached, create it */
if (!gtt_storage_attached(tab->relid)) {
ResultRelInfo *resultRelInfo;
MemoryContext oldcontext;
MemoryContext ctx_alter_gtt;
ctx_alter_gtt =
AllocSetContextCreate(CurrentMemoryContext, "gtt alter table", ALLOCSET_DEFAULT_SIZES);
oldcontext = MemoryContextSwitchTo(ctx_alter_gtt);
resultRelInfo = makeNode(ResultRelInfo);
InitResultRelInfo(resultRelInfo, OldHeap, 1, 0);
if (resultRelInfo->ri_RelationDesc->rd_rel->relhasindex &&
resultRelInfo->ri_IndexRelationDescs == NULL)
ExecOpenIndices(resultRelInfo);
init_gtt_storage(CMD_UTILITY, resultRelInfo);
ExecCloseIndices(resultRelInfo);
(void)MemoryContextSwitchTo(oldcontext);
MemoryContextDelete(ctx_alter_gtt);
}
}
/*
* Select destination tablespace (same as original unless user
* requested a change)
@ -8245,15 +8346,16 @@ static void ATExecAddStatistics(Relation rel, Node* def, LOCKMODE lockmode)
VacAttrStats** vacattrstats_array = es_build_vacattrstats_array(rel, (List*)def, true, &array_length, inh);
if (array_length > 0) {
update_attstats(relid, relkind, false, array_length, vacattrstats_array);
update_attstats(relid, relkind, false, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
if (RelationIsDfsStore(rel)) {
/* HDFS complex table */
update_attstats(relid, relkind, true, array_length, vacattrstats_array);
update_attstats(relid, relkind, true, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
/* HDFS delta table */
Oid delta_relid = rel->rd_rel->reldeltarelid;
Assert(OidIsValid(delta_relid));
update_attstats(delta_relid, relkind, false, array_length, vacattrstats_array);
update_attstats(
delta_relid, relkind, false, array_length, vacattrstats_array, RelationGetRelPersistence(rel));
}
}
}
@ -9117,6 +9219,13 @@ static void ATAddForeignKeyConstraint(AlteredTableInfo* tab, Relation rel, Const
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on temporary tables must involve temporary tables of this session")));
break;
case RELPERSISTENCE_GLOBAL_TEMP:
if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_GLOBAL_TEMP) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on global temporary tables may reference only global temporary tables")));
}
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
@ -12195,6 +12304,12 @@ static void ATExecSetRelOptions(Relation rel, List* defList, AlterTableType oper
if (defList == NIL && operation != AT_ReplaceRelOptions)
return; /* nothing to do */
if (GttOncommitOption(defList) != ONCOMMIT_NOOP) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("table cannot add or modify on commit parameter by ALTER TABLE command.")));
}
/* forbid user to set or change inner options */
ForbidOutUsersToSetInnerOptions(defList);
@ -12465,7 +12580,7 @@ static void ATExecSetTableSpaceForPartitionP2(AlteredTableInfo* tab, Relation re
rangePartDef = (RangePartitionDefState*)partition;
transformRangePartitionValue(make_parsestate(NULL), (Node*)rangePartDef, false);
rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs,
((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey,
((RangePartitionMap*)rel->partMap)->partitionKey,
rangePartDef->boundary);
partOid =
partitionValuesGetPartitionOid(rel, rangePartDef->boundary, AccessExclusiveLock, true, false, false);
@ -12614,7 +12729,7 @@ static void atexecset_table_space_internal(Relation rel, Oid newTableSpace, Oid
* NOTE: any conflict in relfilenode value will be caught in
* RelationCreateStorage function.
*/
RelationCreateStorage(newrnode, rel->rd_rel->relpersistence, rel->rd_rel->relowner, rel->rd_bucketoid);
RelationCreateStorage(newrnode, rel->rd_rel->relpersistence, rel->rd_rel->relowner, rel->rd_bucketoid, rel);
/* copy main fork */
copy_relation_data(rel, &dstrel, MAIN_FORKNUM, rel->rd_rel->relpersistence);
@ -12727,6 +12842,11 @@ static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmo
*/
rel = relation_open(tableOid, lockmode);
if (RELATION_IS_GLOBAL_TEMP(rel)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("not support alter table set tablespace on global temp table.")));
}
/*
* No work if no change in tablespace.
*/
@ -15131,14 +15251,7 @@ void PreCommit_on_commit_actions(void)
/* Do nothing (there shouldn't be such entries, actually) */
break;
case ONCOMMIT_DELETE_ROWS:
/*
* If this transaction hasn't accessed any temporary
* relations, we can skip truncating ON COMMIT DELETE ROWS
* tables, as they must still be empty.
*/
if (t_thrd.xact_cxt.MyXactAccessedTempRel)
oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
break;
case ONCOMMIT_DROP: {
ObjectAddress object;
@ -15549,17 +15662,11 @@ List* GetPartitionkeyPos(List* partitionkeys, List* schema)
* Description :
* Notes :
*/
void CheckPartitionKeyType(Form_pg_attribute* attrs, List* pos, bool is_interval)
static void CheckRangePartitionKeyType(Form_pg_attribute* attrs, List* pos)
{
int location = 0;
ListCell* cell = NULL;
Oid typoid = InvalidOid;
/* must be one partitionkey for interval partition */
if (is_interval && pos->length != 1) {
list_free_ext(pos);
ereport(
ERROR, (errcode(ERRCODE_INVALID_OPERATION), errmsg("must be one partition key for interval partition")));
}
foreach (cell, pos) {
bool result = false;
location = lfirst_int(cell);
@ -15577,6 +15684,23 @@ void CheckPartitionKeyType(Form_pg_attribute* attrs, List* pos, bool is_interval
}
}
static void CheckIntervalPartitionKeyType(Form_pg_attribute* attrs, List* pos)
{
/* must be one partitionkey for interval partition, have checked before */
Assert(pos->length == 1);
ListCell* cell = list_head(pos);
int location = lfirst_int(cell);
Oid typoid = attrs[location]->atttypid;
if (typoid != TIMESTAMPOID && typoid != TIMESTAMPTZOID) {
list_free_ext(pos);
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column %s cannot serve as a interval partitioning column because of its datatype",
NameStr(attrs[location]->attname))));
}
}
/*
* @@GaussDB@@
* Target : value-partition type check
@ -15953,6 +16077,11 @@ static void ATPrepAddPartition(Relation rel)
ereport(
ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not add partition against NON-PARTITIONED table")));
}
if (rel->partMap->type == PART_TYPE_INTERVAL) {
ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
errmsg("can not add partition against interval partitioned table")));
}
}
/*
@ -16063,6 +16192,11 @@ static void ATPrepMergePartition(Relation rel)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not merge partition against NON-PARTITIONED table")));
}
if (rel->partMap->type == PART_TYPE_INTERVAL) {
ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
errmsg("can not merge partition against interval partitioned table")));
}
}
static void ATPrepSplitPartition(Relation rel)
@ -16071,6 +16205,11 @@ static void ATPrepSplitPartition(Relation rel)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not split partition against NON-PARTITIONED table")));
}
if (rel->partMap->type == PART_TYPE_INTERVAL) {
ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
errmsg("can not split partition against interval partitioned table")));
}
}
/*
@ -16224,8 +16363,43 @@ static void ATExecAddPartition(Relation rel, AddPartitionState* partState)
pfree_ext(isTimestamptz);
}
// assume caller already hold AccessExclusiveLock on the partition being dropped
void fastDropPartition(Relation rel, Oid partOid, const char* stmt)
/* Assume the caller has already hold RowExclusiveLock on the pg_partition. */
static void UpdateIntervalPartToRange(Relation relPartition, Oid partOid, const char* stmt)
{
bool dirty = false;
/* Fetch a copy of the tuple to scribble on */
HeapTuple parttup = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(partOid));
if (!HeapTupleIsValid(parttup)) {
ereport(ERROR,
(errcode(ERRCODE_SQL_ROUTINE_EXCEPTION),
errmsg("pg_partition entry for partid %u vanished during %s.", partOid, stmt)));
}
Form_pg_partition partform = (Form_pg_partition)GETSTRUCT(parttup);
/* Apply required updates, if any, to copied tuple */
if (partform->partstrategy == PART_STRATEGY_INTERVAL) {
partform->partstrategy = PART_STRATEGY_RANGE;
dirty = true;
} else {
ereport(LOG,
(errcode(ERRCODE_SQL_ROUTINE_EXCEPTION),
errmsg("pg_partition entry for partid %u is not a interval "
"partition when execute %s .",
partOid,
stmt)));
}
/* If anything changed, write out the tuple. */
if (dirty) {
heap_inplace_update(relPartition, parttup);
}
}
/* assume caller already hold AccessExclusiveLock on the partition being dropped
* if the intervalPartOid is not InvalidOid, the interval partition which is specificed by it
* need to be changed to normal range partition.
*/
void fastDropPartition(Relation rel, Oid partOid, const char* stmt, Oid intervalPartOid)
{
Partition part = NULL;
Relation pg_partition = NULL;
@ -16240,6 +16414,7 @@ void fastDropPartition(Relation rel, Oid partOid, const char* stmt)
getPartitionName(partOid, false),
stmt)));
}
/* drop toast table, index, and finally the partition iteselt */
dropIndexForPartition(partOid);
dropToastTableOnPartition(partOid);
@ -16249,6 +16424,10 @@ void fastDropPartition(Relation rel, Oid partOid, const char* stmt)
}
heapDropPartition(rel, part);
if (intervalPartOid) {
UpdateIntervalPartToRange(pg_partition, intervalPartOid, stmt);
}
/* step 3: no need to update number of partitions in pg_partition */
/* step 4: invalidate relation */
CacheInvalidateRelcache(rel);
@ -16291,8 +16470,7 @@ static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd)
/* next IS the DROP PARTITION FOR (MAXVALUELIST) branch */
rangePartDef = (RangePartitionDefState*)cmd->def;
rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs,
((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey,
rangePartDef->boundary);
((RangePartitionMap*)rel->partMap)->partitionKey, rangePartDef->boundary);
partOid = partitionValuesGetPartitionOid(rel,
rangePartDef->boundary,
AccessExclusiveLock,
@ -16311,7 +16489,9 @@ static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION), errmsg("Cannot drop the only partition of a partitioned table")));
}
fastDropPartition(rel, partOid, "DROP PARTITION");
Oid changeToRangePartOid = GetNeedDegradToRangePartOid(rel, partOid);
fastDropPartition(rel, partOid, "DROP PARTITION", changeToRangePartOid);
}
/*
@ -16565,7 +16745,6 @@ static void ATExecModifyRowMovement(Relation rel, bool rowMovement)
/* get the tuple of partitioned table */
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tuple)) {
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("could not find tuple for relation %u", relid)));
}
@ -16671,7 +16850,7 @@ static void ATExecTruncatePartition(Relation rel, AlterTableCmd* cmd)
} else {
rangePartDef = (RangePartitionDefState*)cmd->def;
rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs,
((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey,
((RangePartitionMap*)rel->partMap)->partitionKey,
rangePartDef->boundary);
partOid = partitionValuesGetPartitionOid(rel,
rangePartDef->boundary,
@ -19298,7 +19477,7 @@ List* transformConstIntoTargetType(Form_pg_attribute* attrs, int2vector* partiti
* Return :
* Notes :
*/
static void addToastTableForNewPartition(Relation relation, Oid newPartId)
void addToastTableForNewPartition(Relation relation, Oid newPartId)
{
Oid firstPartitionId = InvalidOid;
Oid firstPartitionToastId = InvalidOid;
@ -21113,3 +21292,32 @@ static void at_timeseries_check(Relation rel, AlterTableCmd* cmd)
}
}
static OnCommitAction GttOncommitOption(const List *options)
{
ListCell *listptr;
OnCommitAction action = ONCOMMIT_NOOP;
foreach(listptr, options) {
DefElem *def = reinterpret_cast<DefElem *>(lfirst(listptr));
if (strcmp(def->defname, "on_commit_delete_rows") == 0) {
bool res = false;
char *sval = defGetString(def);
if (!parse_bool(sval, &res)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("parameter \"on_commit_delete_rows\" requires a Boolean value")));
}
if (res) {
action = ONCOMMIT_DELETE_ROWS;
} else {
action = ONCOMMIT_PRESERVE_ROWS;
}
break;
}
}
return action;
}

View File

@ -1480,8 +1480,7 @@ static void makeRangeConstructors(const char* name, Oid nmspace, Oid rangeOid, O
F_FMGR_INTERNAL_VALIDATOR, /* language validator */
prosrc[i], /* prosrc */
NULL, /* probin */
false, /* isAgg */
false, /* isWindowFunc */
PROKIND_FUNCTION, /* prokind */
false, /* security_definer */
false, /* leakproof */
false, /* isStrict */

View File

@ -39,6 +39,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pgxc_class.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "commands/cluster.h"
#include "commands/tablespace.h"
#include "commands/vacuum.h"
@ -975,6 +976,16 @@ void vac_update_relstats(Relation relation, Relation classRel, RelPageType num_p
bool isNull = false;
TransactionId relfrozenxid;
Datum xid64datum;
bool isGtt = false;
/* global temp table remember relstats to localhash and rel->rd_rel, not catalog */
if (RELATION_IS_GLOBAL_TEMP(relation)) {
isGtt = true;
up_gtt_relstats(relation,
static_cast<unsigned int>(num_pages), num_tuples,
num_all_visible_pages,
frozenxid);
}
/* Fetch a copy of the tuple to scribble on */
ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@ -989,17 +1000,23 @@ void vac_update_relstats(Relation relation, Relation classRel, RelPageType num_p
// frozenxid == BootstrapTransactionId means it was invoked by execRemote.cpp:ReceivePageAndTuple()
if (IS_PGXC_DATANODE || (frozenxid == BootstrapTransactionId) || IsSystemRelation(relation)) {
#endif
if (pgcform->relpages - num_pages != 0) {
pgcform->relpages = num_pages;
dirty = true;
}
if (pgcform->reltuples - num_tuples != 0) {
pgcform->reltuples = num_tuples;
dirty = true;
}
if (pgcform->relallvisible != (int32)num_all_visible_pages) {
pgcform->relallvisible = (int32)num_all_visible_pages;
dirty = true;
if (isGtt) {
relation->rd_rel->relpages = (int32) num_pages;
relation->rd_rel->reltuples = (float4) num_tuples;
relation->rd_rel->relallvisible = (int32) num_all_visible_pages;
} else {
if (pgcform->relpages - num_pages != 0) {
pgcform->relpages = num_pages;
dirty = true;
}
if (pgcform->reltuples - num_tuples != 0) {
pgcform->reltuples = num_tuples;
dirty = true;
}
if (pgcform->relallvisible != (int32)num_all_visible_pages) {
pgcform->relallvisible = (int32)num_all_visible_pages;
dirty = true;
}
}
#ifdef PGXC
}
@ -1144,6 +1161,11 @@ void vac_update_datfrozenxid(void)
if (classForm->relkind != RELKIND_RELATION && classForm->relkind != RELKIND_TOASTVALUE)
continue;
/* global temp table relstats not in pg_class */
if (classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
xid64datum = heap_getattr(classTup, Anum_pg_class_relfrozenxid64, RelationGetDescr(relation), &isNull);
if (isNull) {
@ -1198,6 +1220,42 @@ void vac_update_datfrozenxid(void)
}
Assert(TransactionIdIsNormal(newFrozenXid));
/*
* Global temp table get frozenxid from MyProc
* to avoid the vacuum truncate clog that gtt need.
*/
if (u_sess->attr.attr_storage.max_active_gtt > 0) {
TransactionId safeAge;
TransactionId oldestGttFrozenxid = ENABLE_THREAD_POOL ?
ListAllSessionGttFrozenxids(0, NULL, NULL, NULL) :
ListAllThreadGttFrozenxids(0, NULL, NULL, NULL);
if (TransactionIdIsNormal(oldestGttFrozenxid)) {
safeAge =
oldestGttFrozenxid + static_cast<TransactionId>(u_sess->attr.attr_storage.vacuum_gtt_defer_check_age);
if (safeAge < FirstNormalTransactionId) {
safeAge += FirstNormalTransactionId;
}
/*
* We tolerate that the minimum age of gtt is less than
* the minimum age of conventional tables, otherwise it will
* throw warning message.
*/
if (TransactionIdIsNormal(safeAge) &&
TransactionIdPrecedes(safeAge, newFrozenXid)) {
ereport(WARNING,
(errmsg(
"global temp table oldest relfrozenxid %lu is the oldest in the entire db", oldestGttFrozenxid),
errdetail("The oldest relfrozenxid in pg_class is %lu", newFrozenXid),
errhint("If they differ greatly, please consider cleaning up the data in global temp table.")));
}
if (TransactionIdPrecedes(oldestGttFrozenxid, newFrozenXid)) {
newFrozenXid = oldestGttFrozenxid;
}
}
}
/* Now fetch the pg_database tuple we need to update. */
relation = heap_open(DatabaseRelationId, RowExclusiveLock);
@ -1610,7 +1668,7 @@ static bool vacuum_rel(Oid relid, VacuumStmt* vacstmt, bool do_toast)
if (onepartrel) {
if (onepartrel->rd_rel->relkind == RELKIND_RELATION) {
partID = partOidGetPartID(onepartrel, relid);
if (partID->partArea == PART_AREA_RANGE) {
if (partID->partArea == PART_AREA_RANGE || partID->partArea == PART_AREA_INTERVAL) {
if (ConditionalLockPartition(onepartrel->rd_id, relid, lmode, PARTITION_LOCK)) {
GetLock = true;
}
@ -1791,6 +1849,13 @@ static bool vacuum_rel(Oid relid, VacuumStmt* vacstmt, bool do_toast)
return false;
}
if (RELATION_IS_GLOBAL_TEMP(onerel) &&
!gtt_storage_attached(RelationGetRelid(onerel))) {
CloseAllRelationsBeforeReturnFalse();
proc_snapshot_and_transaction();
return false;
}
/*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
@ -2263,9 +2328,7 @@ void vac_open_part_indexes(
Assert(vacstmt->onepartrel != NULL);
indexoidlist = PartitionGetPartIndexList(vacstmt->onepart);
i = list_length(indexoidlist);
if (i > 0) {
*Irel = (Relation*)palloc((long)(i) * sizeof(Relation));
*indexrel = (Relation*)palloc((long)(i) * sizeof(Relation));

View File

@ -49,6 +49,7 @@
#include "catalog/catalog.h"
#include "catalog/storage.h"
#include "catalog/pg_hashbucket_fn.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
#include "miscadmin.h"

View File

@ -475,6 +475,12 @@ void DefineView(ViewStmt* stmt, const char* queryString, bool isFirstNode)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("views cannot be unlogged because they do not have storage")));
if (stmt->view->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("views cannot be global temp because they do not have storage")));
}
/*
* If the user didn't explicitly ask for a temporary view, check whether
* we need one implicitly. We allow TEMP to be inserted automatically as

View File

@ -2394,8 +2394,13 @@ static bool qual_is_pushdown_safe(Query* subquery, Index rti, Node* qual, const
ListCell* vl = NULL;
/* Refuse subselects (point 1) */
if (contain_subplans(qual))
if (contain_subplans(qual)) {
return false;
}
if(contain_volatile_functions(qual)) {
return false;
}
/*
* It would be unsafe to push down window function calls, but at least for

View File

@ -5859,8 +5859,10 @@ ForeignScan* make_foreignscan(
plan->righttree = NULL;
plan->exec_type = type;
plan->distributed_keys = NIL;
#ifdef ENABLE_MULTIPLE_NODES
plan->distributed_keys =
lappend(plan->distributed_keys, makeVar(0, InvalidAttrNumber, InvalidOid, -1, InvalidOid, 0));
#endif
node->scan.scanrelid = scanrelid;
node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;

View File

@ -350,7 +350,6 @@ static List* deconstruct_recurse(
*/
foreach (l, (List*)f->quals) {
Node* qual = (Node*)lfirst(l);
distribute_qual_to_rels(
root, qual, false, below_outer_join, JOIN_INNER, root->qualSecurityLevel, *qualscope, NULL, NULL, NULL);
}

View File

@ -1018,6 +1018,7 @@ Plan* subquery_planner(PlannerGlobal* glob, Query* parse, PlannerInfo* parent_ro
root->rowMarks = NIL;
root->hasInheritedTarget = false;
root->grouping_map = NULL;
root->hasRownumQual = false;
/*
* Apply memory context for query rewrite in optimizer.

View File

@ -89,6 +89,8 @@ static Node* find_jointree_node_for_rel(Node* jtnode, int relid);
static Node* deleteRelatedNullTest(Node* node, PlannerInfo* root);
static Node* reduce_inequality_fulljoins_jointree_recurse(PlannerInfo* root, Node* jtnode);
static bool find_rownum_in_quals(PlannerInfo *root);
/*
* pull_up_sublinks
* Attempt to pull up ANY and EXISTS SubLinks to be treated as
@ -122,6 +124,11 @@ void pull_up_sublinks(PlannerInfo* root)
Node* jtnode = NULL;
Relids relids;
/* if quals include rownum, forbid pulling up sublinks */
if (find_rownum_in_quals(root)) {
return;
}
/* Begin recursion through the jointree */
jtnode = pull_up_sublinks_jointree_recurse(root, (Node*)root->parse->jointree, &relids);
/*
@ -744,6 +751,12 @@ Node* pull_up_subqueries(
{
if (jtnode == NULL)
return NULL;
/* if quals include rownum, set hasRownumQual to true */
if(find_rownum_in_quals(root)) {
root->hasRownumQual = true;
}
if (IsA(jtnode, RangeTblRef)) {
int varno = ((RangeTblRef*)jtnode)->rtindex;
RangeTblEntry* rte = rt_fetch(varno, root->parse->rtable);
@ -775,7 +788,7 @@ Node* pull_up_subqueries(
* the branchs may be in different node group, we could not determine the
* group for append path
*/
if (rte->rtekind == RTE_SUBQUERY && is_simple_union_all(rte->subquery) &&
if (rte->rtekind == RTE_SUBQUERY && is_simple_union_all(rte->subquery) && !root->hasRownumQual &&
(!ng_is_multiple_nodegroup_scenario()))
return pull_up_simple_union_all(root, jtnode, rte);
@ -924,6 +937,7 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
subroot->qualSecurityLevel = 0;
subroot->wt_param_id = -1;
subroot->non_recursive_plan = NULL;
subroot->hasRownumQual = root->hasRownumQual;
/* No CTEs to worry about */
AssertEreport(
@ -2886,3 +2900,30 @@ static Node* reduce_inequality_fulljoins_jointree_recurse(PlannerInfo* root, Nod
return jtnode;
}
static bool find_rownum_in_quals(PlannerInfo *root)
{
if (root->parse == NULL) {
return false;
}
if(root->hasRownumQual) {
return true;
}
bool hasRownum = false;
ListCell *qualcell = NULL;
List *quallist = get_quals_lists((Node *)root->parse->jointree);
foreach (qualcell, quallist) {
Node *clause = (Node *)lfirst(qualcell);
if (contain_rownum_walker(clause, NULL)) {
hasRownum = true;
break;
}
}
if (quallist) {
list_free(quallist);
}
return hasRownum;
}

View File

@ -2785,7 +2785,9 @@ List* QueryRewriteCTAS(Query* parsetree)
/*
* Check consistency of arguments
*/
if (create_stmt->oncommit != ONCOMMIT_NOOP && create_stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
if (create_stmt->oncommit != ONCOMMIT_NOOP &&
(create_stmt->relation->relpersistence != RELPERSISTENCE_TEMP &&
create_stmt->relation->relpersistence != RELPERSISTENCE_GLOBAL_TEMP))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables")));

View File

@ -1119,6 +1119,9 @@ static bool contain_specified_functions_walker(Node* node, check_function_contex
return true;
}
/* else fall through to check args */
} else if (IsA(node, Rownum)) {
/* ROWNUM is volatile */
return context->checktype == CONTAIN_VOLATILE_FUNTION;
}
return expression_tree_walker(node, (bool (*)())contain_specified_functions_walker<isSimpleVar>, context);
}
@ -5161,8 +5164,51 @@ static Node* convert_equalsimplevar_to_nulltest(Oid opno, List* args)
rarg = (Node*)lsecond(args);
if (_equalSimpleVar(larg, rarg) && ((Var*)larg)->varlevelsup == ((Var*)rarg)->varlevelsup &&
(get_oprrest(opno) == EQSELRETURNOID))
(get_oprrest(opno) == EQSELRETURNOID)) {
nullTest = (Node*)makeNullTest(IS_NOT_NULL, (Expr*)larg);
}
return nullTest;
}
/*
* check whether the node have rownum expr or not, test all kinds of nodes,
* check if it has the volatile rownum. If the node include rownum
* function, it will return true, else it will return false.
*/
bool contain_rownum_walker(Node *node, void *context)
{
if (node == NULL) {
return false;
}
if (IsA(node, Rownum)) {
return true;
}
return expression_tree_walker(node, (bool (*)())contain_rownum_walker, context);
}
/*
* get the jtnode's qualifiers list, make query tree's table jion tree's
* qualifiers to be a list. Then return the list. (parse->jointree->quals:
* 'where clause' and 'and clause')
*/
List *get_quals_lists(Node *jtnode)
{
if (jtnode == NULL || !IsA(jtnode, FromExpr)) {
return NULL;
}
FromExpr *expr = (FromExpr *)jtnode;
List *quallist = make_ands_implicit((Expr *)expr->quals);
if (expr->quals != NULL && and_clause((Node *)expr->quals)) {
quallist = list_copy(quallist);
}
return quallist;
}

View File

@ -27,6 +27,7 @@
#include "catalog/pg_partition_fn.h"
#include "catalog/pg_statistic.h"
#include "catalog/heap.h"
#include "catalog/storage_gtt.h"
#include "commands/dbcommands.h"
#include "executor/nodeModifyTable.h"
#include "foreign/fdwapi.h"
@ -73,9 +74,7 @@ static void acquireSamplesForPartitionedRelation(
if (RelationIsPartitioned(relation)) {
if (relation->rd_rel->relkind == RELKIND_RELATION) {
RangePartitionMap* partMap = (RangePartitionMap*)(relation->partMap);
int totalRangePartitionNumber = getNumberOfRangePartitions(relation);
int totalInervalPartitionNumber = getNumberOfIntervalPartitions(relation);
int totalPartitionNumber = totalRangePartitionNumber + totalInervalPartitionNumber;
int totalPartitionNumber = getNumberOfRangePartitions(relation);
int partitionNumber = 0;
int nonzeroPartitionNumber = 0;
BlockNumber partPages = 0;
@ -83,24 +82,7 @@ static void acquireSamplesForPartitionedRelation(
Partition part = NULL;
for (partitionNumber = 0; partitionNumber < totalPartitionNumber; partitionNumber++) {
Oid partitionOid = InvalidOid;
#ifdef PGXC // open range partition
partitionOid = partMap->rangeElements[partitionNumber].partitionOid;
#else // open range partition or interval partition
if (partitionNumber < totalRangePartitionNumber) {
partitionOid = partMap->rangeElements[partitionNumber].partitionOid;
} else {
IntervalPartitionMap* intervalPartMap = NULL;
int intervalPartitionIndex = partitionNumber - totalRangePartitionNumber;
AssertEreport(relation->partMap->type == PART_TYPE_INTERVAL,
MOD_OPT,
"Expected interval partition type but exception occurred.");
intervalPartMap = (IntervalPartitionMap*)(relation->partMap);
partitionOid = intervalPartMap->intervalElements[intervalPartitionIndex].partitionOid;
}
#endif
Oid partitionOid = partMap->rangeElements[partitionNumber].partitionOid;
if (!OidIsValid(partitionOid))
continue;
@ -251,6 +233,12 @@ void get_relation_info(PlannerInfo* root, Oid relationObjectId, bool inhparent,
continue;
}
/* Ignore empty index for global temp table */
if (RELATION_IS_GLOBAL_TEMP(indexRelation) &&
!gtt_storage_attached(RelationGetRelid(indexRelation))) {
index_close(indexRelation, NoLock);
continue;
}
/*
* If the index is valid, but cannot yet be used, ignore it; but
* mark the plan we are generating as transient. See

View File

@ -140,7 +140,7 @@ bool checkPartitionIndexUnusable(Oid indexOid, int partItrs, PruningResult* prun
heapRel = relation_open(heapRelOid, NoLock);
indexRel = relation_open(indexOid, NoLock);
if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel) ||
heapRel->partMap->type != PART_TYPE_RANGE) {
(heapRel->partMap->type != PART_TYPE_RANGE && heapRel->partMap->type != PART_TYPE_INTERVAL)) {
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
@ -226,8 +226,7 @@ IndexesUsableType eliminate_partition_index_unusable(Oid indexOid, PruningResult
heapRel = relation_open(heapRelOid, NoLock);
indexRel = relation_open(indexOid, NoLock);
if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel) ||
heapRel->partMap->type != PART_TYPE_RANGE) {
if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel)) {
ereport(ERROR,
(errmodule(MOD_OPT),
(errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
@ -438,7 +437,7 @@ PruningResult* singlePartitionPruningForRestrictInfo(Oid partitionOid, Relation
pruningRes->state = PRUNING_RESULT_SUBSET;
/* it's a pattitioned table without interval */
if (rel->partMap->type == PART_TYPE_RANGE) {
if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) {
rangePartMap = (RangePartitionMap*)rel->partMap;
for (counter = 0; counter < rangePartMap->rangeElementsNum; counter++) {
@ -1152,13 +1151,13 @@ int varIsInPartitionKey(int attrNo, int2vector* partKeyAttrs, int partKeyNum)
(PruningResultIsFull(pruningResult) || PruningResultIsEmpty(pruningResult) || \
!PointerIsValid((pruningResult)->boundary))
#define IsCleanPruningBottom(bottomSeqPtr, pruningResult, bottomValue) \
((bottomSeqPtr)->partArea == PART_AREA_RANGE && (pruningResult)->boundary->partitionKeyNum > 1 && \
PointerIsValid((bottomValue)[0]) && !(pruningResult)->boundary->minClose[0])
#define IsCleanPruningBottom(bottomSeqPtr, pruningResult, bottomValue) \
((pruningResult)->boundary->partitionKeyNum > 1 && PointerIsValid((bottomValue)[0]) && \
!(pruningResult)->boundary->minClose[0])
#define IsCleanPruningTop(topSeqPtr, pruningResult, topValue) \
((topSeqPtr)->partArea == PART_AREA_RANGE && (pruningResult)->boundary->partitionKeyNum > 1 && (topValue) && \
PointerIsValid((topValue)[0]) && !(pruningResult)->boundary->maxClose[0])
#define IsCleanPruningTop(topSeqPtr, pruningResult, topValue) \
((pruningResult)->boundary->partitionKeyNum > 1 && (topValue) && PointerIsValid((topValue)[0]) && \
!(pruningResult)->boundary->maxClose[0])
/*
* @@GaussDB@@
@ -1209,13 +1208,14 @@ static void partitionPruningFromBoundary(Relation relation, PruningResult* pruni
// compare the bottom and the intervalMax, if the bottom is large than or equal than intervalMax, pruning result is
// empty.
partitionRoutingForValue(
partitionRoutingForValueRange(
relation, bottomValue, pruningResult->boundary->partitionKeyNum, true, true, u_sess->opt_cxt.bottom_seq);
if (IsCleanPruningBottom(u_sess->opt_cxt.bottom_seq, pruningResult, bottomValue)) {
cleanPruningBottom(relation, u_sess->opt_cxt.bottom_seq, bottomValue[0]);
}
partitionRoutingForValue(
relation, topValue, pruningResult->boundary->partitionKeyNum, isTopClosed, true, u_sess->opt_cxt.top_seq);
partitionRoutingForValueRange(
relation, topValue, pruningResult->boundary->partitionKeyNum, isTopClosed, false, u_sess->opt_cxt.top_seq);
if (IsCleanPruningTop(u_sess->opt_cxt.top_seq, pruningResult, topValue)) {
cleanPruningTop(relation, u_sess->opt_cxt.top_seq, topValue[0]);
}
@ -1226,22 +1226,14 @@ static void partitionPruningFromBoundary(Relation relation, PruningResult* pruni
if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq) && !PartitionLogicalExist(u_sess->opt_cxt.top_seq)) {
/* pruning failed or result contains all partition */
pruningResult->state = PRUNING_RESULT_EMPTY;
} else if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq) &&
u_sess->opt_cxt.top_seq->partArea == PART_AREA_RANGE) {
} else if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq)) {
rangeStart = 0;
rangeEnd = u_sess->opt_cxt.top_seq->partSeq;
} else if (u_sess->opt_cxt.bottom_seq->partArea == PART_AREA_RANGE &&
!PartitionLogicalExist(u_sess->opt_cxt.top_seq)) {
} else if (!PartitionLogicalExist(u_sess->opt_cxt.top_seq)) {
rangeStart = u_sess->opt_cxt.bottom_seq->partSeq;
} else if (u_sess->opt_cxt.bottom_seq->partArea == PART_AREA_RANGE &&
u_sess->opt_cxt.top_seq->partArea == PART_AREA_RANGE) {
} else {
rangeStart = u_sess->opt_cxt.bottom_seq->partSeq;
rangeEnd = u_sess->opt_cxt.top_seq->partSeq;
} else {
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
errmsg("pruning result(PartitionIdentifier) is invalid")));
}
if (0 <= rangeStart) {
@ -1655,8 +1647,8 @@ static void cleanPruningBottom(Relation relation, PartitionIdentifier* bottomSeq
int i = 0;
RangePartitionMap* partMap = NULL;
if (bottomSeq->partArea != PART_AREA_RANGE || bottomSeq->partSeq < 0 ||
bottomSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || value == NULL) {
if (bottomSeq->partSeq < 0 || bottomSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum ||
value == NULL) {
return;
}
@ -1688,8 +1680,8 @@ static void cleanPruningTop(Relation relation, PartitionIdentifier* topSeq, Cons
int i = 0;
RangePartitionMap* partMap = NULL;
if (topSeq->partArea != PART_AREA_RANGE || topSeq->partSeq < 0 ||
topSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || value == NULL) {
if (topSeq->partSeq < 0 || topSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum ||
value == NULL) {
return;
}
@ -1853,7 +1845,7 @@ Oid getPartitionOidFromSequence(Relation relation, int partSeq)
AssertEreport(PointerIsValid(relation), MOD_OPT, "Unexpected NULL pointer for relation.");
AssertEreport(PointerIsValid(relation->partMap), MOD_OPT, "Unexpected NULL pointer for relation->partMap.");
if (relation->partMap->type == PART_TYPE_RANGE) {
if (relation->partMap->type == PART_TYPE_RANGE || relation->partMap->type == PART_TYPE_INTERVAL) {
int rangeElementsNum = ((RangePartitionMap*)(relation->partMap))->rangeElementsNum;
if (partSeq < rangeElementsNum) {
result = ((RangePartitionMap*)(relation->partMap))->rangeElements[partSeq].partitionOid;

View File

@ -2170,8 +2170,10 @@ static void do_autovacuum(void)
bool enable_vacuum = false;
/* We cannot safely process other backends' temp tables, so skip 'em. */
if (RELPERSISTENCE_TEMP == classForm->relpersistence)
if (classForm->relpersistence == RELPERSISTENCE_TEMP ||
classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
/* Fetch reloptions for this table */
relopts = extract_autovac_opts(tuple, pg_class_desc);
@ -2414,7 +2416,8 @@ static void do_autovacuum(void)
av_toastid_mainid* at_entry = NULL;
/* We cannot safely process other backends' temp tables, so skip 'em. */
if (classForm->relpersistence == RELPERSISTENCE_TEMP)
if (classForm->relpersistence == RELPERSISTENCE_TEMP ||
classForm->relpersistence == RELPERSISTENCE_GLOBAL_TEMP)
continue;
at_entry = (av_toastid_mainid*)hash_search(toast_table_map, &(relid), HASH_FIND, &found);

View File

@ -10207,8 +10207,12 @@ Datum disable_conn(PG_FUNCTION_ARGS)
ereport(
ERROR, (errcode(ERRCODE_INVALID_ATTRIBUTE), errmsg("Invalid null pointer attribute for disable_conn()")));
}
char* host;
if (!superuser()) {
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser account to perform disable_conn()")));
}
char* host;
const char* disconn_mode = TextDatumGetCString(arg0);
ValidateName(disconn_mode);

24
src/gausskernel/process/tcop/utility.cpp Executable file → Normal file
View File

@ -2779,7 +2779,7 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi
switch (((DropStmt*)parse_tree)->removeType) {
case OBJECT_INDEX:
#ifdef PGXC
#ifdef ENABLE_MULTIPLE_NODES
if (((DropStmt*)parse_tree)->concurrent) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -3586,7 +3586,7 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi
} break;
case T_AlterDomainStmt:
#ifdef PGXC
#ifdef ENABLE_MULTIPLE_NODES
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("domain is not yet supported.")));
#endif /* PGXC */
{
@ -3928,10 +3928,10 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi
} break;
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
#ifdef PGXC
#ifdef ENABLE_MULTIPLE_NODES
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("user defined range type is not yet supported.")));
#endif /* PGXC */
#endif /* ENABLE_MULTIPLE_NODES */
DefineRange((CreateRangeStmt*)parse_tree);
#ifdef PGXC
if (IS_PGXC_COORDINATOR)
@ -4140,12 +4140,14 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi
is_first_node = (strcmp(first_exec_node, g_instance.attr.attr_common.PGXCNodeName) == 0);
}
#ifdef ENABLE_MULTIPLE_NODES
if (stmt->concurrent) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PGXC does not support concurrent INDEX yet"),
errdetail("The feature is not currently supported")));
}
#endif
/* INDEX on a temporary table cannot use 2PC at commit */
rel_id = RangeVarGetRelidExtended(stmt->relation, AccessShareLock, true, false, false, true, NULL, NULL);
@ -4927,12 +4929,12 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi
* ******************************** DOMAIN statements ****
*/
case T_CreateDomainStmt:
#ifdef PGXC
#ifdef ENABLE_MULTIPLE_NODES
if (!IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("domain is not yet supported.")));
#endif /* PGXC */
DefineDomain((CreateDomainStmt*)parse_tree);
#ifdef PGXC
#ifdef ENABLE_MULTIPLE_NODES
if (IS_PGXC_COORDINATOR)
ExecUtilityStmtOnNodes(query_string, NULL, sent_to_remote, false, EXEC_ON_ALL_NODES, false);
#endif
@ -8504,7 +8506,8 @@ bool DropExtensionIsSupported(const char* query_string)
{
char* lower_string = lowerstr(query_string);
if (strstr(lower_string, "drop") && (strstr(lower_string, "postgis") || strstr(lower_string, "packages"))) {
if (strstr(lower_string, "drop") && (strstr(lower_string, "postgis") || strstr(lower_string, "packages") ||
strstr(lower_string, "mysql_fdw") || strstr(lower_string, "oracle_fdw"))) {
pfree_ext(lower_string);
return true;
} else {
@ -8563,9 +8566,10 @@ void CheckObjectInBlackList(ObjectType obj_type, const char* query_string)
case OBJECT_LANGUAGE:
tag = "LANGUAGE";
break;
case OBJECT_DOMAIN:
/*Single node support domain feature.*/
/* case OBJECT_DOMAIN:
tag = "DOMAIN";
break;
break;*/
case OBJECT_CONVERSION:
tag = "CONVERSION";
break;
@ -8595,7 +8599,7 @@ void CheckObjectInBlackList(ObjectType obj_type, const char* query_string)
*/
bool CheckExtensionInWhiteList(const char* extension_name, uint32 hash_value, bool hash_check)
{
/* 2902411162 hash for fastcheck, the sql file is much shorter than published version. */
/* 2902411162 hash for fastcheck, the sql file is much shorter than published version. */
uint32 postgisHashHistory[POSTGIS_VERSION_NUM] = {2902411162, 2959454932};
/* check for extension name */

View File

@ -743,6 +743,19 @@ static void knl_u_storage_init(knl_u_storage_context* storage_cxt)
storage_cxt->twoPhaseCommitInProgress = false;
storage_cxt->dumpHashbucketIdNum = 0;
storage_cxt->dumpHashbucketIds = NULL;
/* session local buffer */
storage_cxt->NLocBuffer = 0; /* until buffers are initialized */
storage_cxt->LocalBufferDescriptors = NULL;
storage_cxt->LocalBufferBlockPointers = NULL;
storage_cxt->LocalRefCount = NULL;
storage_cxt->nextFreeLocalBuf = 0;
storage_cxt->LocalBufHash = NULL;
storage_cxt->cur_block = NULL;
storage_cxt->next_buf_in_block = 0;
storage_cxt->num_bufs_in_block = 0;
storage_cxt->total_bufs_allocated = 0;
storage_cxt->LocalBufferContext = NULL;
}
static void knl_u_libpq_init(knl_u_libpq_context* libpq_cxt)

View File

@ -1148,17 +1148,6 @@ static void knl_t_storage_init(knl_t_storage_context* storage_cxt)
storage_cxt->smoothed_alloc = 0;
storage_cxt->smoothed_density = 10.0;
storage_cxt->StrategyControl = NULL;
storage_cxt->NLocBuffer = 0; /* until buffers are initialized */
storage_cxt->LocalBufferDescriptors = NULL;
storage_cxt->LocalBufferBlockPointers = NULL;
storage_cxt->LocalRefCount = NULL;
storage_cxt->nextFreeLocalBuf = 0;
storage_cxt->LocalBufHash = NULL;
storage_cxt->cur_block = NULL;
storage_cxt->next_buf_in_block = 0;
storage_cxt->num_bufs_in_block = 0;
storage_cxt->total_bufs_allocated = 0;
storage_cxt->LocalBufferContext = NULL;
storage_cxt->CacheBlockInProgressIO = CACHE_BLOCK_INVALID_IDX;
storage_cxt->CacheBlockInProgressUncompress = CACHE_BLOCK_INVALID_IDX;
storage_cxt->MetaBlockInProgressIO = CACHE_BLOCK_INVALID_IDX;
@ -1407,7 +1396,6 @@ static void knl_t_mot_init(knl_t_mot_context* mot_cxt)
mot_cxt->bindPolicy = 2; // MPOL_BIND
mot_cxt->mbindFlags = 0;
mot_cxt->mot_startup = false;
}
void knl_thread_mot_init()

View File

@ -269,6 +269,9 @@ void ExecReScan(PlanState* node)
InstrEndLoop(node->instrument);
}
/* reset the rownum */
node->ps_rownum = 0;
/*
* If we have changed parameters, propagate that info.
*

View File

@ -1045,6 +1045,11 @@ void ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
if (isTempNamespace(get_rel_namespace(rte->relid))) {
continue;
}
if (get_rel_persistence(rte->relid) == RELPERSISTENCE_GLOBAL_TEMP) {
continue;
}
if (rte->relid == PgxcNodeRelationId && g_instance.attr.attr_storage.IsRoachStandbyCluster &&
u_sess->attr.attr_common.xc_maintenance_mode) {
continue;

View File

@ -560,6 +560,8 @@ PlanState* ExecInitNode(Plan* node, EState* e_state, int e_flags)
/* restore the per query context */
e_state->es_query_cxt = query_context;
result->ps_rownum = 0;
gstrace_exit(GS_TRC_ID_ExecInitNode);
return result;
}
@ -743,6 +745,8 @@ TupleTableSlot* ExecProcNode(PlanState* node)
MemoryContextSwitchTo(old_context);
node->ps_rownum++;
return result;
}

View File

@ -969,6 +969,19 @@ static Datum ExecEvalConst(ExprState* exprstate, ExprContext* econtext, bool* is
return con->constvalue;
}
/* ----------------------------------------------------------------
* ExecEvalRownum: Returns the rownum
* ----------------------------------------------------------------
*/
static Datum ExecEvalRownum(RownumState* exprstate, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
{
if (isDone != NULL)
*isDone = ExprSingleResult;
*isNull = false;
return Int8GetDatum(exprstate->ps->ps_rownum + 1);
}
/* ----------------------------------------------------------------
* ExecEvalParamExec
*
@ -5232,6 +5245,12 @@ ExprState* ExecInitExpr(Expr* node, PlanState* parent)
gstrace_exit(GS_TRC_ID_ExecInitExpr);
return (ExprState*)outlist;
}
case T_Rownum: {
RownumState* rnstate = (RownumState*)makeNode(RownumState);
rnstate->ps = parent;
state = (ExprState*)rnstate;
state->evalfunc = (ExprStateEvalFunc)ExecEvalRownum;
} break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),

View File

@ -43,6 +43,7 @@
#include "catalog/heap.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_partition_fn.h"
#include "catalog/storage_gtt.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#ifdef PGXC
@ -1216,7 +1217,6 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid,
/* for partitioned table */
bool row_movement = false;
bool need_create_file = false;
int seq_num = -1;
if (!partKeyUpdate) {
row_movement = false;
@ -1257,7 +1257,6 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid,
if (result_relation_desc->rd_rel->relrowmovement) {
row_movement = true;
need_create_file = true;
seq_num = u_sess->exec_cxt.route->partSeq;
} else {
ereport(ERROR,
(errmodule(MOD_EXECUTOR),
@ -1519,7 +1518,7 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid,
Relation fake_insert_relation = NULL;
if (need_create_file) {
new_partId = createNewIntervalFile(result_relation_desc, seq_num);
new_partId = AddNewIntervalPartition(result_relation_desc, tuple);
}
searchFakeReationForPartitionOid(estate->esfRelations,
@ -2163,7 +2162,7 @@ ModifyTableState* ExecInitModifyTable(ModifyTable* node, EState* estate, int efl
result_rel_info->ri_FdwRoutine->GetFdwType() != MOT_ORC)
ExecOpenIndices(result_rel_info);
}
init_gtt_storage(operation, result_rel_info);
/* Now init the plan for this result rel */
estate->es_result_relation_info = result_rel_info;
mt_state->mt_plans[i] = ExecInitNode(sub_plan, estate, eflags);

View File

@ -29,6 +29,7 @@
#include "access/printtup.h"
#include "access/transam.h"
#include "catalog/pg_aggregate.h"
#include "catalog/storage_gtt.h"
#include "commands/copy.h"
#include "executor/nodeIndexscan.h"
#include "gstrace/executer_gstrace.h"
@ -1099,7 +1100,7 @@ bool InsertFusion::execute(long max_rows, char* completionTag)
CommandId mycid = GetCurrentCommandId(true);
refreshParameterIfNecessary();
init_gtt_storage(CMD_INSERT, result_rel_info);
/************************
* step 2: begin insert *
************************/

View File

@ -85,6 +85,7 @@ static relopt_bool boolRelOpts[] = {
{{"multi_zall", "segmente all word from long words in zhparser text search praser", RELOPT_KIND_ZHPARSER}, false},
{{"ignore_enable_hadoop_env", "ignore enable_hadoop_env option", RELOPT_KIND_HEAP}, false},
{{"hashbucket", "Enables hashbucket in this relation", RELOPT_KIND_HEAP}, false},
{{"on_commit_delete_rows", "global temp table on commit options", RELOPT_KIND_HEAP}, true},
/* list terminator */
{{NULL}}};
@ -1490,7 +1491,8 @@ bytea* default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"start_ctid_internal", RELOPT_TYPE_STRING, offsetof(StdRdOptions, start_ctid_internal)},
{"end_ctid_internal", RELOPT_TYPE_STRING, offsetof(StdRdOptions, end_ctid_internal)},
{"user_catalog_table", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, user_catalog_table)},
{"hashbucket", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, hashbucket)}};
{"hashbucket", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, hashbucket)},
{"on_commit_delete_rows", RELOPT_TYPE_BOOL, offsetof(StdRdOptions, on_commit_delete_rows)}};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
@ -2034,3 +2036,30 @@ bytea* tsearch_config_reloptions(Datum tsoptions, bool validate, Oid prsoid, boo
return (bytea*)cfopts;
}
/* remove an option from options list. If succeeded, set removed = true */
List* RemoveRelOption(List* options, const char* optName, bool* removed)
{
ListCell* lcell = NULL;
DefElem* opt = NULL;
bool found = false;
foreach (lcell, options) {
opt = (DefElem*)lfirst(lcell);
if (strncmp(opt->defname, optName, strlen(optName)) == 0) {
found = true;
break;
}
}
if (found) {
options = list_delete_ptr(options, opt);
pfree_ext(opt);
}
if (removed != NULL) {
*removed = found;
}
return options;
}

View File

@ -7362,10 +7362,6 @@ Partition partitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmode,
/* Get the lock before trying to open the relcache entry */
if (lockmode != NoLock) {
if (relation->rd_rel->relkind == RELKIND_RELATION) {
/*
* assume the partition is in PART_AREA_RANGE, if we support interval partition,
* we have to find a quick way to find the area it belongs to.
*/
LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
} else if (relation->rd_rel->relkind == RELKIND_INDEX) {
LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
@ -7427,6 +7423,9 @@ Partition tryPartitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmod
case PART_AREA_RANGE:
LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
break;
case PART_AREA_INTERVAL:
LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
break;
default:
break;
}
@ -7456,6 +7455,9 @@ Partition tryPartitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmod
case PART_AREA_RANGE:
UnlockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
break;
case PART_AREA_INTERVAL:
UnlockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK);
break;
default:
break;
}
@ -7524,6 +7526,9 @@ void partitionClose(Relation relation, Partition partition, LOCKMODE lockmode)
case PART_AREA_RANGE:
UnlockPartition(relation->rd_id, part->pd_id, lockmode, PARTITION_LOCK);
break;
case PART_AREA_INTERVAL:
UnlockPartition(relation->rd_id, part->pd_id, lockmode, PARTITION_LOCK);
break;
default:
break;
}

Some files were not shown because too many files have changed in this diff Show More