mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-29 07:50:04 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
002fdb33fc | ||
|
|
13b65c9a6a | ||
|
|
e6118a06e8 | ||
|
|
63ac71190b | ||
|
|
37542ae706 | ||
|
|
89d4d835ba | ||
|
|
9f0ea70945 | ||
|
|
86e4a88201 | ||
|
|
c002881f66 | ||
|
|
f17d4530a3 | ||
|
|
94a76cc9e0 | ||
|
|
4c0b229b14 | ||
|
|
17d0d5e0a2 | ||
|
|
f97d29243d | ||
|
|
94864104e4 | ||
|
|
6988ce96d7 | ||
|
|
98492e7718 | ||
|
|
becb453e7d | ||
|
|
35644fdd35 | ||
|
|
5ab056759b | ||
|
|
e1aeaba942 | ||
|
|
e256fc32d9 | ||
|
|
a7ba446703 | ||
|
|
26d0a3e5cb | ||
|
|
7f571fa7d8 | ||
|
|
cb600549c3 | ||
|
|
e1cb6d92c5 | ||
|
|
8812a7db69 | ||
|
|
96361656e4 | ||
|
|
83785da1bc | ||
|
|
4fe69e825e | ||
|
|
6105fc861d | ||
|
|
f156696339 | ||
|
|
b6c8707a4d | ||
|
|
3031c5055a | ||
|
|
44c0d76541 | ||
|
|
0b101d9efd | ||
|
|
b69995b34d | ||
|
|
ef6c9fbd6d | ||
|
|
e43f58d11f | ||
|
|
a684b48fb3 | ||
|
|
7cc30e3216 | ||
|
|
6586be5158 | ||
|
|
1bd14895c3 | ||
|
|
82155cd859 | ||
|
|
0ed3cd248b |
No files matched your search
+5
-3
@@ -1,8 +1,6 @@
|
||||
*.autosave
|
||||
*.db
|
||||
*.diff
|
||||
*.o
|
||||
*.patch
|
||||
*.psp
|
||||
*.pyc
|
||||
*.pyo
|
||||
@@ -11,14 +9,18 @@
|
||||
.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
/*.diff
|
||||
/*.patch
|
||||
/dist
|
||||
/debian-build
|
||||
/docker-build
|
||||
/mac-build
|
||||
/pip-build
|
||||
/redhat-build
|
||||
/src-build
|
||||
/win-build
|
||||
_build
|
||||
build-*
|
||||
/build-*
|
||||
pgadmin4.log
|
||||
pkg/win32/installer.iss
|
||||
pkg/mac/codesign.conf
|
||||
|
||||
@@ -91,7 +91,7 @@ runtime:
|
||||
cd runtime && qmake CONFIG+=release && make
|
||||
|
||||
# Include all clean sub-targets in clean
|
||||
clean: clean-appbundle clean-dist clean-docs clean-node clean-pip clean-src clean-runtime
|
||||
clean: clean-appbundle clean-debian clean-dist clean-docs clean-node clean-pip clean-redhat clean-src clean-runtime
|
||||
rm -rf web/pgadmin/static/js/generated/*
|
||||
rm -rf web/pgadmin/static/js/generated/.cache
|
||||
rm -rf web/pgadmin/static/css/generated/*
|
||||
@@ -104,6 +104,9 @@ clean-runtime:
|
||||
clean-appbundle:
|
||||
rm -rf mac-build/
|
||||
|
||||
clean-debian:
|
||||
rm -rf debian-build/
|
||||
|
||||
clean-dist:
|
||||
rm -rf dist/
|
||||
|
||||
@@ -116,9 +119,15 @@ clean-node:
|
||||
clean-pip:
|
||||
rm -rf pip-build/
|
||||
|
||||
clean-redhat:
|
||||
rm -rf redhat-build/
|
||||
|
||||
clean-src:
|
||||
rm -rf src-build/
|
||||
|
||||
debian:
|
||||
./pkg/debian/build.sh
|
||||
|
||||
docker:
|
||||
echo $(APP_NAME)
|
||||
docker build -t ${APP_NAME} -t $(APP_NAME):latest -t $(APP_NAME):$(APP_RELEASE) -t $(APP_NAME):$(APP_RELEASE).$(APP_REVISION) .
|
||||
@@ -148,5 +157,8 @@ msg-update:
|
||||
pip: docs
|
||||
./pkg/pip/build.sh
|
||||
|
||||
redhat:
|
||||
./pkg/redhat/build.sh
|
||||
|
||||
src:
|
||||
./pkg/src/build.sh
|
||||
@@ -11,6 +11,7 @@ notes for it.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_4_20
|
||||
release_notes_4_19
|
||||
release_notes_4_18
|
||||
release_notes_4_17
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
************
|
||||
Version 4.20
|
||||
************
|
||||
|
||||
Release date: 2020-04-02
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.19.
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #5261 <https://redmine.postgresql.org/issues/5261>`_ - Added support of Collation, FTS Configuration, FTS Dictionary, FTS Parser and FTS Template to the Schema Diff.
|
||||
| `Issue #5262 <https://redmine.postgresql.org/issues/5262>`_ - Added support of Domain, Domain Constraints and Types to the Schema Diff.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #5271 <https://redmine.postgresql.org/issues/5271>`_ - Enhance the color of switch control for both light and dark theme.
|
||||
| `Issue #5284 <https://redmine.postgresql.org/issues/5284>`_ - Added and fixed gettext usage for better translation coverage.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #4237 <https://redmine.postgresql.org/issues/4237>`_ - Fix an issue where the user can not change the value of DateTime picker control using keyboard.
|
||||
| `Issue #4608 <https://redmine.postgresql.org/issues/4608>`_ - Fixed some accessibility issues in the dialogs.
|
||||
| `Issue #4942 <https://redmine.postgresql.org/issues/4942>`_ - Fixed chrome driver download utility issue for Ubuntu.
|
||||
| `Issue #5128 <https://redmine.postgresql.org/issues/5128>`_ - Change some colors and opacity to comply with WCAG color contrast standards.
|
||||
| `Issue #5143 <https://redmine.postgresql.org/issues/5143>`_ - Fix an accessibility issue to maximize the panel for all alertify dialog.
|
||||
| `Issue #5221 <https://redmine.postgresql.org/issues/5221>`_ - Improve logic to get the DDL statements as a part of the comparison.
|
||||
| `Issue #5241 <https://redmine.postgresql.org/issues/5241>`_ - Fixed tab key navigation issue for Grant Wizard.
|
||||
| `Issue #5279 <https://redmine.postgresql.org/issues/5279>`_ - Fixed Unicode character issue causing error on Python2 environment.
|
||||
| `Issue #5292 <https://redmine.postgresql.org/issues/5292>`_ - Fixed focus color issue for Alertify dialog buttons.
|
||||
@@ -0,0 +1,47 @@
|
||||
This directory contains the build runner script for creating .DEB packages for
|
||||
Debian and Ubuntu.
|
||||
|
||||
Build configuration
|
||||
===================
|
||||
|
||||
To build Debian/Ubuntu packages, first run the setup.sh script as root to
|
||||
install the required pre-requisites, e.g.
|
||||
|
||||
# pkg/debian/setup.sh
|
||||
|
||||
Building packages
|
||||
=================
|
||||
|
||||
To build a set of packages, from the top-level source directory run:
|
||||
|
||||
$ make debian
|
||||
|
||||
or
|
||||
|
||||
$ pkg/debian/build.sh
|
||||
|
||||
Four .deb packages will be created in the dist/ directory:
|
||||
|
||||
pgadmin4_<version>_<distro>_<distro_version>_all.deb
|
||||
A convenience package that depends on all the others.
|
||||
|
||||
pgadmin4-server_<version>_<distro>_<distro_version>_<arch>.deb
|
||||
The core server, e.g. the Python and JS code and the online documentation.
|
||||
|
||||
pgadmin4-desktop_<version>_<distro>_<distro_version>_<arch>.deb
|
||||
The desktop runtime. Requires the server package.
|
||||
|
||||
pgadmin4-web_<version>_<distro>_<distro_version>_<arch>.deb
|
||||
The server mode setup script for configuring Apache HTTPD. Requires the
|
||||
server package.
|
||||
|
||||
Supported platforms
|
||||
===================
|
||||
|
||||
Debian 9 & 10
|
||||
Ubuntu 16.04, 18.04, 19.04 & 19.10
|
||||
|
||||
Warning
|
||||
=======
|
||||
|
||||
These scripts are experimental - use at your own risk!
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit when any command fails
|
||||
set -e
|
||||
|
||||
# Debugging shizz
|
||||
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
|
||||
trap 'if [ $? -ne 0 ]; then echo "\"${last_command}\" command filed with exit code $?."; fi' EXIT
|
||||
|
||||
OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
OS_NAME=$(cat /etc/os-release | grep "^ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
OS_ARCH=$(dpkg-architecture -qDEB_HOST_ARCH)
|
||||
|
||||
# Common Linux build functions
|
||||
source pkg/linux/build-functions.sh
|
||||
|
||||
# Assemble the "standard" installation footprint
|
||||
_setup_env $0 "debian"
|
||||
_cleanup "deb"
|
||||
_setup_dirs
|
||||
_create_python_virtualenv "debian"
|
||||
_build_runtime
|
||||
_build_docs "debian"
|
||||
_copy_code
|
||||
|
||||
#
|
||||
# Server package
|
||||
#
|
||||
|
||||
# Create the Debian packaging stuffs for the server
|
||||
echo "Creating the server package..."
|
||||
mkdir "${SERVERROOT}/DEBIAN"
|
||||
|
||||
cat << EOF > "${SERVERROOT}/DEBIAN/control"
|
||||
Package: ${APP_NAME}-server
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Architecture: ${OS_ARCH}
|
||||
Depends: python3, libpq5
|
||||
Recommends: postgresql-client | postgresql-client-12 | postgresql-client-11 | postgresql-client-10
|
||||
Maintainer: pgAdmin Development Team <pgadmin-hackers@postgresql.org>
|
||||
Description: The core server package for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
EOF
|
||||
|
||||
# Build the Debian package for the server
|
||||
fakeroot dpkg-deb --build "${SERVERROOT}" "${DISTROOT}/${APP_NAME}-server_${APP_LONG_VERSION}_${OS_ARCH}.deb"
|
||||
|
||||
#
|
||||
# Desktop package
|
||||
#
|
||||
|
||||
# Create the Debian packaging stuffs for the desktop
|
||||
echo "Creating the desktop package..."
|
||||
mkdir "${DESKTOPROOT}/DEBIAN"
|
||||
|
||||
cat << EOF > "${DESKTOPROOT}/DEBIAN/control"
|
||||
Package: ${APP_NAME}-desktop
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Architecture: ${OS_ARCH}
|
||||
Depends: ${APP_NAME}-server, libqt5gui5
|
||||
Maintainer: pgAdmin Development Team <pgadmin-hackers@postgresql.org>
|
||||
Description: The desktop user interface for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
EOF
|
||||
|
||||
# Build the Debian package for the server
|
||||
fakeroot dpkg-deb --build "${DESKTOPROOT}" "${DISTROOT}/${APP_NAME}-desktop_${APP_LONG_VERSION}_${OS_ARCH}.deb"
|
||||
|
||||
#
|
||||
# Web package
|
||||
#
|
||||
|
||||
# Create the Debian packaging stuffs for the web
|
||||
echo "Creating the web package..."
|
||||
mkdir "${WEBROOT}/DEBIAN"
|
||||
|
||||
cat << EOF > "${WEBROOT}/DEBIAN/control"
|
||||
Package: ${APP_NAME}-web
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Architecture: all
|
||||
Depends: ${APP_NAME}-server, apache2, libapache2-mod-wsgi-py3
|
||||
Maintainer: pgAdmin Development Team <pgadmin-hackers@postgresql.org>
|
||||
Description: The web interface for pgAdmin, hosted under Apache HTTPD. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
EOF
|
||||
|
||||
mkdir -p "${WEBROOT}/etc/apache2/conf-available"
|
||||
cp "${SOURCEDIR}/pkg/debian/pgadmin4.conf" "${WEBROOT}/etc/apache2/conf-available"
|
||||
|
||||
# Build the Debian package for the web
|
||||
fakeroot dpkg-deb --build "${WEBROOT}" "${DISTROOT}/${APP_NAME}-web_${APP_LONG_VERSION}_all.deb"
|
||||
|
||||
#
|
||||
# Meta package
|
||||
#
|
||||
|
||||
# Create the Debian packaging stuffs for the meta package
|
||||
echo "Creating the meta package..."
|
||||
mkdir "${METAROOT}/DEBIAN"
|
||||
|
||||
cat << EOF > "${METAROOT}/DEBIAN/control"
|
||||
Package: ${APP_NAME}
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Architecture: all
|
||||
Depends: ${APP_NAME}-server, ${APP_NAME}-desktop, ${APP_NAME}-web
|
||||
Maintainer: pgAdmin Development Team <pgadmin-hackers@postgresql.org>
|
||||
Description: Installs all required components to run pgAdmin in desktop and web modes. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
EOF
|
||||
|
||||
# Build the Debian meta package
|
||||
fakeroot dpkg-deb --build "${METAROOT}" "${DISTROOT}/${APP_NAME}_${APP_LONG_VERSION}_all.deb"
|
||||
@@ -0,0 +1,9 @@
|
||||
WSGIDaemonProcess pgadmin processes=1 threads=25 python-home=/usr/pgadmin4/venv
|
||||
WSGIScriptAlias /pgadmin4 /usr/pgadmin4/web/pgAdmin4.wsgi
|
||||
|
||||
<Directory /usr/pgadmin4/web/>
|
||||
WSGIProcessGroup pgadmin
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing system pre-requisites..."
|
||||
apt install -y curl apt-transport-https ca-certificates
|
||||
|
||||
echo "Removing yarn (which may not be the package we expect)..."
|
||||
dpkg -r yarn
|
||||
|
||||
# Node repo
|
||||
echo "Setting up the NodeJS repo..."
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
|
||||
# Yarn repo
|
||||
echo "Setting up the Yarn repo..."
|
||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
|
||||
echo "Running apt update..."
|
||||
apt update
|
||||
|
||||
# Install pre-reqs
|
||||
echo "Installing build pre-requisites..."
|
||||
apt install -y build-essential python3-dev python3-venv python3-sphinx libpq-dev libffi-dev qt5-default nodejs yarn
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
This directory contains package build scripts and assets that are common to various Linux distributions.
|
||||
|
||||
You should not use them directly!
|
||||
@@ -0,0 +1,161 @@
|
||||
_setup_env() {
|
||||
echo "Setting up the environment..."
|
||||
WD=$(cd `dirname "$1"` && pwd)
|
||||
SOURCEDIR=$(realpath "${WD}/../..")
|
||||
BUILDROOT=$(realpath "${WD}/../../$2-build")
|
||||
DESKTOPROOT=${BUILDROOT}/desktop
|
||||
METAROOT=${BUILDROOT}/meta
|
||||
SERVERROOT=${BUILDROOT}/server
|
||||
WEBROOT=${BUILDROOT}/web
|
||||
DISTROOT=$(realpath "${WD}/../../dist")
|
||||
APP_RELEASE=`grep "^APP_RELEASE" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
|
||||
APP_REVISION=`grep "^APP_REVISION" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
|
||||
APP_NAME=`grep "^APP_NAME" web/config.py | cut -d"=" -f2 | sed "s/'//g" | sed 's/^ //' | sed 's/ //g' | tr '[:upper:]' '[:lower:]'`
|
||||
APP_LONG_VERSION=${APP_RELEASE}.${APP_REVISION}
|
||||
APP_SHORT_VERSION=`echo ${APP_LONG_VERSION} | cut -d . -f1,2`
|
||||
APP_SUFFIX=`grep "^APP_SUFFIX" web/config.py | cut -d"=" -f2 | sed 's/ //g' | sed "s/'//g"`
|
||||
if [ ! -z ${APP_SUFFIX} ]; then
|
||||
APP_LONG_VERSION=${APP_LONG_VERSION}-${APP_SUFFIX}
|
||||
fi
|
||||
}
|
||||
|
||||
_cleanup() {
|
||||
echo "Cleaning up the old environment and app..."
|
||||
if test -f ${SOURCEDIR}/runtime/pgAdmin4; then
|
||||
rm -rf ${SOURCEDIR}/runtime/pgAdmin4
|
||||
fi
|
||||
if test -d ${BUILDROOT}; then
|
||||
rm -rf ${BUILDROOT}
|
||||
fi
|
||||
rm -f ${DISTROOT}/pgadmin4*.$1
|
||||
}
|
||||
|
||||
_setup_dirs() {
|
||||
echo "Creating output directories..."
|
||||
test -d ${BUILDROOT} || mkdir ${BUILDROOT}
|
||||
test -d ${DESKTOPROOT} || mkdir ${DESKTOPROOT}
|
||||
test -d ${METAROOT} || mkdir ${METAROOT}
|
||||
test -d ${SERVERROOT} || mkdir ${SERVERROOT}
|
||||
test -d ${WEBROOT} || mkdir ${WEBROOT}
|
||||
test -d ${DISTROOT} || mkdir ${DISTROOT}
|
||||
}
|
||||
|
||||
_create_python_virtualenv() {
|
||||
echo "Creating the virtual environment..."
|
||||
|
||||
cd ${SERVERROOT}
|
||||
|
||||
# Create the required directories
|
||||
mkdir -p "usr/${APP_NAME}"
|
||||
cd "usr/${APP_NAME}"
|
||||
|
||||
# Create the blank venv
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
pip3 install --no-cache-dir --no-binary psycopg2 -r ${SOURCEDIR}/requirements.txt
|
||||
|
||||
# Figure out some paths for use when completing the venv
|
||||
# Use "python3" here as we want the venv path
|
||||
PYMODULES_PATH=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
|
||||
DIR_PYMODULES_PATH=`dirname ${PYMODULES_PATH}`
|
||||
|
||||
# Use /usr/bin/python3 here as we want the system path
|
||||
if [ $1 == "debian" ]; then
|
||||
PYSYSLIB_PATH=$(/usr/bin/python3 -c "import sys; print('%s/lib/python%d.%.d' % (sys.prefix, sys.version_info.major, sys.version_info.minor))")
|
||||
else
|
||||
PYSYSLIB_PATH=$(/usr/bin/python3 -c "import sys; print('%s/lib64/python%d.%.d' % (sys.prefix, sys.version_info.major, sys.version_info.minor))")
|
||||
fi
|
||||
|
||||
# Symlink in the rest of the Python libs. This is required because the runtime
|
||||
# will clear PYTHONHOME for safety, which has the side-effect of preventing
|
||||
# it from finding modules that are not explicitly included in the venv
|
||||
cd ${DIR_PYMODULES_PATH}
|
||||
|
||||
# Files
|
||||
for FULLPATH in ${PYSYSLIB_PATH}/*.py; do
|
||||
FILE=${FULLPATH##*/}
|
||||
if [ ! -e ${FILE} ]; then
|
||||
ln -s ${FULLPATH} ${FILE}
|
||||
fi
|
||||
done
|
||||
|
||||
# Paths
|
||||
for FULLPATH in ${PYSYSLIB_PATH}/*/; do
|
||||
FULLPATH=${FULLPATH%*/}
|
||||
FILE=${FULLPATH##*/}
|
||||
if [ ! -e ${FILE} ]; then
|
||||
ln -s ${FULLPATH} ${FILE}
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove tests
|
||||
cd site-packages
|
||||
find . -name "test" -type d -print0 | xargs -0 rm -rf
|
||||
find . -name "tests" -type d -print0 | xargs -0 rm -rf
|
||||
|
||||
# Link the python<version> directory to python so that the private environment path is found by the application.
|
||||
if test -d ${DIR_PYMODULES_PATH}; then
|
||||
ln -s $(basename ${DIR_PYMODULES_PATH}) ${DIR_PYMODULES_PATH}/../python
|
||||
fi
|
||||
}
|
||||
|
||||
_build_runtime() {
|
||||
echo "Building the desktop runtime..."
|
||||
cd ${SOURCEDIR}/runtime
|
||||
if [ -f Makefile ]; then
|
||||
make clean
|
||||
fi
|
||||
if hash qmake-qt5 2>/dev/null; then
|
||||
qmake-qt5
|
||||
else
|
||||
qmake
|
||||
fi
|
||||
make
|
||||
mkdir -p "${DESKTOPROOT}/usr/${APP_NAME}/bin"
|
||||
cp pgAdmin4 "${DESKTOPROOT}/usr/${APP_NAME}/bin/pgadmin4"
|
||||
mkdir -p "${DESKTOPROOT}/usr/${APP_NAME}/share"
|
||||
cp pgAdmin4.ico "${DESKTOPROOT}/usr/${APP_NAME}/share/pgadmin4.ico"
|
||||
mkdir -p "${DESKTOPROOT}/usr/share/applications"
|
||||
cp ../pkg/linux/pgadmin4.desktop "${DESKTOPROOT}/usr/share/applications"
|
||||
}
|
||||
|
||||
_build_docs() {
|
||||
echo "Building the documentation..."
|
||||
cd "${SERVERROOT}" && mkdir -p "usr/${APP_NAME}/share/docs/en_US/html"
|
||||
cd "${SOURCEDIR}/docs/en_US"
|
||||
python3 build_code_snippet.py
|
||||
SYS_PYTHONPATH=$(/usr/bin/python3 -c "import sys; print(':'.join([p for p in sys.path if p]))")
|
||||
if [ $1 == "redhat" -a "${OS_VERSION}" == "7" ]; then
|
||||
PYTHONPATH=$PYTHONPATH:${SYS_PYTHONPATH} python3 /usr/local/bin/sphinx-build . "${SERVERROOT}/usr/${APP_NAME}/share/docs/en_US/html"
|
||||
else
|
||||
PYTHONPATH=$PYTHONPATH:${SYS_PYTHONPATH} python3 -msphinx . "${SERVERROOT}/usr/${APP_NAME}/share/docs/en_US/html"
|
||||
fi
|
||||
}
|
||||
|
||||
_copy_code() {
|
||||
echo "Copying the server code..."
|
||||
|
||||
# Remove any TCL-related files that may cause us problems
|
||||
find "${SERVERROOT}/usr/${APP_NAME}/venv/" -name "_tkinter*" -print0 | xargs -0 rm -rf
|
||||
|
||||
pushd ${SOURCEDIR}/web
|
||||
yarn install
|
||||
yarn run bundle
|
||||
popd
|
||||
|
||||
# copy the web directory to the bundle as it is required by runtime
|
||||
cp -r "${SOURCEDIR}/web" "${SERVERROOT}/usr/${APP_NAME}/web/"
|
||||
cp "${SOURCEDIR}/pkg/linux/config_distro.py" "${SERVERROOT}/usr/${APP_NAME}/web/"
|
||||
cd "${SERVERROOT}/usr/${APP_NAME}/web/"
|
||||
rm -f pgadmin4.db config_local.*
|
||||
rm -rf karma.conf.js package.json node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache
|
||||
find . -name "tests" -type d -print0 | xargs -0 rm -rf
|
||||
find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf
|
||||
find . -name "__pycache__" -type d -print0 | xargs -0 rm -rf
|
||||
|
||||
# Web setup script
|
||||
mkdir -p "${WEBROOT}/usr/${APP_NAME}/bin/"
|
||||
cp "${SOURCEDIR}/pkg/linux/setup-web.sh" "${WEBROOT}/usr/${APP_NAME}/bin/"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
HELP_PATH = '../../../share/docs/en_US/html/'
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
'pg': '/usr/bin',
|
||||
'ppas': ''
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=pgAdmin 4
|
||||
Exec=/usr/pgadmin4/bin/pgadmin4
|
||||
Icon=/usr/pgadmin4/share/pgadmin4.ico
|
||||
Type=Application
|
||||
Categories=Application;Development;
|
||||
MimeType=text/html
|
||||
Comment=Management tools for PostgreSQL
|
||||
Keywords=database;db;sql;query;administration;development;
|
||||
Executable
+107
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Setup pgadmin4 in server mode
|
||||
#
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the distro
|
||||
IS_REDHAT=0
|
||||
IS_DEBIAN=0
|
||||
UNAME=$(uname -a)
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
IS_REDHAT=1
|
||||
APACHE=httpd
|
||||
echo "Setting up pgAdmin 4 in web mode on a Redhat platform..."
|
||||
elif [[ ${UNAME} =~ "Ubuntu" ]] || [[ ${UNAME} =~ "debian" ]]; then
|
||||
IS_DEBIAN=1
|
||||
APACHE=apache2
|
||||
echo "Setting up pgAdmin 4 in web mode on a Debian platform..."
|
||||
fi
|
||||
|
||||
# Run setup script first:
|
||||
echo "Creating configuration database..."
|
||||
/usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py
|
||||
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "Error setting up server mode. Please examine the output above."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create and own directories:
|
||||
echo "Creating storage and log directories..."
|
||||
mkdir -p /var/log/pgadmin /var/lib/pgadmin
|
||||
|
||||
if [ ${IS_REDHAT} == 1 ]; then
|
||||
chown apache: /var/log/pgadmin /var/lib/pgadmin -R
|
||||
else
|
||||
chown www-data: /var/log/pgadmin /var/lib/pgadmin -R
|
||||
fi
|
||||
|
||||
# Set SELinux up:
|
||||
if [ ${IS_REDHAT} == 1 ]; then
|
||||
echo "Configuring SELinux..."
|
||||
setsebool -P httpd_can_network_connect 1
|
||||
setsebool -P httpd_can_network_connect_db 1
|
||||
semanage fcontext -a -t httpd_var_lib_t '/var/lib/pgadmin(/.*)?'
|
||||
restorecon -R -v /var/lib/pgadmin
|
||||
semanage fcontext -a -t httpd_log_t '/var/log/pgadmin(/.*)?'
|
||||
restorecon -R -v /var/log/pgadmin
|
||||
fi
|
||||
|
||||
# Setup Apache on Debian/Ubuntu
|
||||
if [ ${IS_DEBIAN} == 1 ]; then
|
||||
read -p "We can now configure the Apache Web server for you. This involves enabling the wsgi module and configuring the pgAdmin 4 application to mount at /pgadmin4. Do you wish to continue (y/n)? " RESPONSE
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
a2enmod wsgi 1> /dev/null
|
||||
a2enconf pgadmin4 1> /dev/null
|
||||
;;
|
||||
* )
|
||||
exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
APACHE_STATUS=`ps cax | grep ${APACHE}`
|
||||
if [ $? -eq 0 ]; then
|
||||
read -p "The Apache web server is running. A restart is required for the pgAdmin 4 installation to complete. Would you like to continue (y/n)? " RESPONSE
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
systemctl restart ${APACHE}
|
||||
if [ $? != 0 ]; then
|
||||
echo "Error restarting ${APACHE}. Please check the systemd logs"
|
||||
else
|
||||
echo "Apache successfully restarted. You can now start using pgAdmin 4 in web mode"
|
||||
fi;;
|
||||
* )
|
||||
exit 1;;
|
||||
esac
|
||||
else
|
||||
read -p "The Apache web server is not running. We can enable and start the web server for you to finish pgAdmin 4 installation. Would you like to continue (y/n)? " RESPONSE
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
systemctl enable ${APACHE}
|
||||
if [ $? != 0 ]; then
|
||||
echo "Error enabling ${APACHE}. Please check the systemd logs"
|
||||
else
|
||||
echo "Apache successfully enabled."
|
||||
fi
|
||||
|
||||
systemctl start ${APACHE}
|
||||
if [ $? != 0 ]; then
|
||||
echo "Error starting ${APACHE}. Please check the systemd logs"
|
||||
else
|
||||
echo "Apache successfully started. You can now start using pgAdmin 4 in web mode"
|
||||
fi;;
|
||||
* )
|
||||
exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,51 @@
|
||||
This directory contains the build runner script for creating .RPM packages for
|
||||
Redhat distributions.
|
||||
|
||||
Build configuration
|
||||
===================
|
||||
|
||||
To build RPM packages, first run the setup.sh script as root to install the
|
||||
required pre-requisites, e.g.
|
||||
|
||||
# pkg/redhat/setup.sh
|
||||
|
||||
Building packages
|
||||
=================
|
||||
|
||||
To build a set of packages, from the top-level source directory run:
|
||||
|
||||
$ make redhat
|
||||
|
||||
or
|
||||
|
||||
$ pkg/redhat/build.sh
|
||||
|
||||
Four .rpm packages will be created in the dist/ directory:
|
||||
|
||||
pgadmin4-<version>.<distro>_noarch.rpm
|
||||
A convenience package that depends on all the others.
|
||||
|
||||
pgadmin4-server-<version>.<distro>.<arch>.rpm
|
||||
The core server, e.g. the Python and JS code and the online documentation.
|
||||
|
||||
pgadmin4-desktop-<version>.<distro>.<arch>.rpm
|
||||
The desktop runtime. Requires the server package.
|
||||
|
||||
pgadmin4-web-<version>.<distro>.<arch>.rpm
|
||||
The server mode setup script for configuring Apache HTTPD. Requires the
|
||||
server package.
|
||||
|
||||
pgadmin4-python3-mod_wsgi-4.7.1-2.el7.<arch>.rpm
|
||||
The Python 3 build of mod_wsgi for the Apache HTTPD server. Only built
|
||||
on RHEL/CentOS 7.
|
||||
|
||||
Supported platforms
|
||||
===================
|
||||
|
||||
Fedora 30 & 31
|
||||
RHEL/CentOS 7 & 8
|
||||
|
||||
Warning
|
||||
=======
|
||||
|
||||
These scripts are experimental - use at your own risk!
|
||||
Executable
+214
@@ -0,0 +1,214 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit when any command fails
|
||||
set -e
|
||||
|
||||
# Debugging shizz
|
||||
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
|
||||
trap 'if [ $? -ne 0 ]; then echo "\"${last_command}\" command filed with exit code $?."; fi' EXIT
|
||||
|
||||
OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
OS_NAME=$(cat /etc/os-release | grep "^ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
OS_ARCH=$(arch)
|
||||
|
||||
# Common Linux build functions
|
||||
source pkg/linux/build-functions.sh
|
||||
|
||||
# Assemble the "standard" installation footprint
|
||||
_setup_env $0 "redhat"
|
||||
_cleanup "rpm"
|
||||
_setup_dirs
|
||||
_create_python_virtualenv "redhat"
|
||||
_build_runtime
|
||||
_build_docs "redhat"
|
||||
_copy_code
|
||||
|
||||
#
|
||||
# Server package
|
||||
#
|
||||
|
||||
# Create the Redhat packaging stuffs for the server
|
||||
echo "Creating the server package..."
|
||||
|
||||
cat << EOF > "${BUILDROOT}/server.spec"
|
||||
%global __requires_exclude_from ^/.*$
|
||||
%global __provides_exclude_from ^/.*$
|
||||
|
||||
# Bytecompiling Python 3 doesn't work on RHEL/CentOS 7, so make it a no-op
|
||||
%if 0%{?rhel} && 0%{?rhel} == 7
|
||||
%define __python /bin/true
|
||||
%endif
|
||||
|
||||
%undefine __brp_mangle_shebangs
|
||||
%undefine __brp_ldconfig
|
||||
|
||||
Name: ${APP_NAME}-server
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Release: 1%{?dist}
|
||||
Summary: The core server package for pgAdmin.
|
||||
License: PostgreSQL
|
||||
URL: https://www.pgadmin.org/
|
||||
%if 0%{?rhel} && 0%{?rhel} != 7
|
||||
Requires: python3, libpq
|
||||
Recommends: postgresql
|
||||
%else
|
||||
Requires: python3, postgresql
|
||||
%endif
|
||||
|
||||
%description
|
||||
The core server package for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
cp -rfa %{pga_build_root}/server/* \${RPM_BUILD_ROOT}
|
||||
|
||||
%files
|
||||
/usr/pgadmin4/*
|
||||
EOF
|
||||
|
||||
# Build the Redhat package for the server
|
||||
rpmbuild --define "pga_build_root ${BUILDROOT}" -bb "${BUILDROOT}/server.spec"
|
||||
|
||||
#
|
||||
# Desktop package
|
||||
#
|
||||
|
||||
# Create the Redhat packaging stuffs for the desktop
|
||||
echo "Creating the desktop package..."
|
||||
|
||||
cat << EOF > "${BUILDROOT}/desktop.spec"
|
||||
%global __requires_exclude_from ^/.*$
|
||||
%global __provides_exclude_from ^/.*$
|
||||
|
||||
%undefine __brp_mangle_shebangs
|
||||
%undefine __brp_ldconfig
|
||||
|
||||
Name: ${APP_NAME}-desktop
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Release: 1%{?dist}
|
||||
Summary: The desktop user interface for pgAdmin.
|
||||
License: PostgreSQL
|
||||
URL: https://www.pgadmin.org/
|
||||
Requires: ${APP_NAME}-server, qt5-qtbase, qt5-qtbase-gui
|
||||
|
||||
%description
|
||||
The desktop user interface for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
cp -rfa %{pga_build_root}/desktop/* \${RPM_BUILD_ROOT}
|
||||
|
||||
%files
|
||||
/usr/pgadmin4/bin/*
|
||||
/usr/pgadmin4/share/*
|
||||
/usr/share/applications/*
|
||||
EOF
|
||||
|
||||
# Build the Redhat package for the server
|
||||
rpmbuild --define "pga_build_root ${BUILDROOT}" -bb "${BUILDROOT}/desktop.spec"
|
||||
|
||||
|
||||
#
|
||||
# Web package
|
||||
#
|
||||
|
||||
# Create the Redhat packaging stuffs for the web
|
||||
echo "Creating the web package..."
|
||||
|
||||
cat << EOF > "${BUILDROOT}/web.spec"
|
||||
%global __requires_exclude_from ^/.*$
|
||||
%global __provides_exclude_from ^/.*$
|
||||
|
||||
%undefine __brp_mangle_shebangs
|
||||
%undefine __brp_ldconfig
|
||||
|
||||
Name: ${APP_NAME}-web
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Release: 1%{?dist}
|
||||
BuildArch: noarch
|
||||
Summary: The web interface for pgAdmin, hosted under Apache HTTPD.
|
||||
License: PostgreSQL
|
||||
URL: https://www.pgadmin.org/
|
||||
%if 0%{?rhel} && 0%{?rhel} == 7
|
||||
Requires: ${APP_NAME}-server, httpd, pgadmin4-python3-mod_wsgi
|
||||
%else
|
||||
Requires: ${APP_NAME}-server, httpd, python3-mod_wsgi
|
||||
%endif
|
||||
|
||||
%description
|
||||
The web interface for pgAdmin, hosted under Apache HTTPD. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
cp -rfa %{pga_build_root}/web/* \${RPM_BUILD_ROOT}
|
||||
|
||||
%files
|
||||
/usr/pgadmin4/bin/*
|
||||
/etc/httpd/conf.d/*
|
||||
EOF
|
||||
|
||||
mkdir -p "${WEBROOT}/etc/httpd/conf.d"
|
||||
cp "${SOURCEDIR}/pkg/redhat/pgadmin4.conf" "${WEBROOT}/etc/httpd/conf.d"
|
||||
|
||||
# Build the Redhat package for the web
|
||||
rpmbuild --define "pga_build_root ${BUILDROOT}" -bb "${BUILDROOT}/web.spec"
|
||||
|
||||
#
|
||||
# Meta package
|
||||
#
|
||||
|
||||
|
||||
# Create the Redhat packaging stuffs for the meta package
|
||||
echo "Creating the meta package..."
|
||||
|
||||
cat << EOF > "${BUILDROOT}/meta.spec"
|
||||
%global __requires_exclude_from ^/.*$
|
||||
%global __provides_exclude_from ^/.*$
|
||||
|
||||
%undefine __brp_mangle_shebangs
|
||||
%undefine __brp_ldconfig
|
||||
|
||||
Name: ${APP_NAME}
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Release: 1%{?dist}
|
||||
BuildArch: noarch
|
||||
Summary: Installs all required components to run pgAdmin in desktop and web modes.
|
||||
License: PostgreSQL
|
||||
URL: https://www.pgadmin.org/
|
||||
Requires: ${APP_NAME}-server, ${APP_NAME}-desktop, ${APP_NAME}-web
|
||||
|
||||
%description
|
||||
Installs all required components to run pgAdmin in desktop and web modes. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
|
||||
%files
|
||||
|
||||
EOF
|
||||
|
||||
# Build the Redhat package for the meta package
|
||||
rpmbuild --define "pga_build_root ${BUILDROOT}" -bb "${BUILDROOT}/meta.spec"
|
||||
|
||||
#
|
||||
# mod_wsgi for CentOS 7
|
||||
#
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
cp "${SOURCEDIR}/pkg/redhat/pgadmin4-python3-mod_wsgi-exports.patch" ${HOME}/rpmbuild/SOURCES
|
||||
cp "${SOURCEDIR}/pkg/redhat/pgadmin4-python3-mod_wsgi.conf" ${HOME}/rpmbuild/SOURCES
|
||||
curl -o ${HOME}/rpmbuild/SOURCES/mod_wsgi-4.7.1.tar.gz https://codeload.github.com/GrahamDumpleton/mod_wsgi/tar.gz/4.7.1
|
||||
rpmbuild -bb "${SOURCEDIR}/pkg/redhat/pgadmin4-python-mod_wsgi.spec"
|
||||
fi
|
||||
|
||||
#
|
||||
# Get the results!
|
||||
#
|
||||
cp ${HOME}/rpmbuild/RPMS/${OS_ARCH}/${APP_NAME}-*${APP_LONG_VERSION}-*.${OS_ARCH}.rpm "${DISTROOT}/"
|
||||
cp ${HOME}/rpmbuild/RPMS/noarch/${APP_NAME}-*${APP_LONG_VERSION}-*.noarch.rpm "${DISTROOT}/"
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
cp ${HOME}/rpmbuild/RPMS/${OS_ARCH}/pgadmin4-python3-mod_wsgi-4.7.1-2.el7.x86_64.rpm "${DISTROOT}/"
|
||||
fi
|
||||
@@ -0,0 +1,71 @@
|
||||
%global sname mod_wsgi
|
||||
|
||||
%{!?_httpd_apxs: %{expand: %%global _httpd_apxs %%{_sbindir}/apxs}}
|
||||
|
||||
%{!?_httpd_mmn: %{expand: %%global _httpd_mmn %%(cat %{_includedir}/httpd/.mmn 2>/dev/null || echo 0-0)}}
|
||||
%{!?_httpd_confdir: %{expand: %%global _httpd_confdir %%{_sysconfdir}/httpd/conf.d}}
|
||||
# /etc/httpd/conf.d with httpd < 2.4 and defined as /etc/httpd/conf.modules.d with httpd >= 2.4
|
||||
%{!?_httpd_modconfdir: %{expand: %%global _httpd_modconfdir %%{_sysconfdir}/httpd/conf.d}}
|
||||
%{!?_httpd_moddir: %{expand: %%global _httpd_moddir %%{_libdir}/httpd/modules}}
|
||||
|
||||
%global debug_package %{nil}
|
||||
|
||||
Name: pgadmin4-python3-%{sname}
|
||||
Version: 4.7.1
|
||||
Release: 2%{?dist}
|
||||
Summary: A WSGI interface for Python web applications in Apache (customized for pgAdmin4)
|
||||
License: ASL 2.0
|
||||
URL: https://modwsgi.readthedocs.io/
|
||||
Source0: https://github.com/GrahamDumpleton/%{sname}/archive/%{version}.tar.gz#/mod_wsgi-%{version}.tar.gz
|
||||
Source2: %{name}.conf
|
||||
Patch1: %{name}-exports.patch
|
||||
|
||||
Requires: httpd-mmn = %{_httpd_mmn}
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: httpd-devel
|
||||
BuildRequires: gcc
|
||||
|
||||
# Suppress auto-provides for module DSO
|
||||
%{?filter_provides_in: %filter_provides_in %{_httpd_moddir}/.*\.so$}
|
||||
%{?filter_setup}
|
||||
|
||||
%global _description\
|
||||
The mod_wsgi adapter is an Apache module that provides a WSGI compliant\
|
||||
interface for hosting Python based web applications within Apache. The\
|
||||
adapter is written completely in C code against the Apache C runtime and\
|
||||
for hosting WSGI applications within Apache has a lower overhead than using\
|
||||
existing WSGI adapters for mod_python or CGI.\
|
||||
|
||||
%description %_description
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n %{sname}-%{version}
|
||||
|
||||
%build
|
||||
export LDFLAGS="$RPM_LD_FLAGS -L%{_libdir}"
|
||||
export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing"
|
||||
|
||||
%configure --enable-shared --with-apxs=%{_httpd_apxs} --with-python=python3
|
||||
%{__make} %{?_smp_mflags}
|
||||
%{_bindir}/python3 setup.py build
|
||||
|
||||
%install
|
||||
%{__make} install DESTDIR=%{buildroot} LIBEXECDIR=%{_httpd_moddir}
|
||||
%{__install} -d -m 755 %{buildroot}%{_httpd_modconfdir}
|
||||
%{__install} -p -m 644 %{SOURCE2} %{buildroot}%{_httpd_modconfdir}/10-pgadmin4-python3-mod_wsgi.conf
|
||||
%{_bindir}/python3 setup.py install -O1 --skip-build --root %{buildroot}
|
||||
%{__mv} %{buildroot}%{_httpd_moddir}/mod_wsgi.so %{buildroot}%{_httpd_moddir}/pgadmin4-python3-mod_wsgi.so
|
||||
%{__mv} %{buildroot}%{_bindir}/mod_wsgi-express %{buildroot}%{_bindir}/pgadmin4-mod_wsgi-express-3
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%doc CREDITS.rst README.rst
|
||||
%config(noreplace) %{_httpd_modconfdir}/*pgadmin4-python3-mod_wsgi.conf
|
||||
%{_httpd_moddir}/pgadmin4-python3-mod_wsgi.so
|
||||
%{python3_sitearch}/mod_wsgi-*.egg-info
|
||||
%{python3_sitearch}/mod_wsgi
|
||||
%{_bindir}/pgadmin4-mod_wsgi-express-3
|
||||
|
||||
%changelog
|
||||
* Fri Mar 6 2020 Devrim Gündüz <devrim@gunduz.org> - 4.6.8-2
|
||||
- Initial packaging for the PostgreSQL YUM repository
|
||||
@@ -0,0 +1,11 @@
|
||||
--- mod_wsgi-4.5.20/Makefile.in.exports
|
||||
+++ mod_wsgi-4.5.20/Makefile.in
|
||||
@@ -28,7 +28,7 @@
|
||||
all : src/server/mod_wsgi.la
|
||||
|
||||
src/server/mod_wsgi.la : $(SRCFILES)
|
||||
- $(APXS) -c $(CPPFLAGS) $(CFLAGS) $(SRCFILES) $(LDFLAGS) $(LDLIBS)
|
||||
+ $(APXS) -Wl,-export-symbols-regex -Wl,wsgi_module -c $(CPPFLAGS) $(CFLAGS) $(SRCFILES) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
$(DESTDIR)$(LIBEXECDIR) :
|
||||
mkdir -p $@
|
||||
@@ -0,0 +1,4 @@
|
||||
<IfModule !wsgi_module>
|
||||
LoadModule wsgi_module modules/pgadmin4-python3-mod_wsgi.so
|
||||
</IfModule>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
LoadModule wsgi_module modules/mod_wsgi.so
|
||||
WSGIDaemonProcess pgadmin processes=1 threads=25 python-home=/usr/pgadmin4/venv
|
||||
WSGIScriptAlias /pgadmin4 /usr/pgadmin4/web/pgAdmin4.wsgi
|
||||
|
||||
<Directory /usr/pgadmin4/web/>
|
||||
WSGIProcessGroup pgadmin
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
<IfModule mod_authz_core.c>
|
||||
# Apache 2.4
|
||||
Require all granted
|
||||
</IfModule>
|
||||
<IfModule !mod_authz_core.c>
|
||||
# Apache 2.2
|
||||
Order Deny,Allow
|
||||
Deny from All
|
||||
Allow from 127.0.0.1
|
||||
Allow from ::1
|
||||
</IfModule>
|
||||
</Directory>
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
|
||||
# EPEL & other repos
|
||||
yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-${OS_VERSION}.noarch.rpm
|
||||
yum config-manager --enable PowerTools AppStream BaseOS *epel
|
||||
|
||||
# Node repo
|
||||
echo "Setting up the NodeJS repo..."
|
||||
curl -sL https://rpm.nodesource.com/setup_12.x | bash -
|
||||
|
||||
# Yarn repo
|
||||
echo "Setting up the Yarn repo..."
|
||||
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
|
||||
|
||||
# Install pre-reqs
|
||||
echo "Installing build pre-requisites..."
|
||||
yum groupinstall -y "Development Tools"
|
||||
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
yum install -y fakeroot httpd-devel qt5-qtbase-devel postgresql-devel python3-devel nodejs yarn rpm-build
|
||||
pip3 install sphinx
|
||||
else
|
||||
yum install -y fakeroot qt5-qtbase-devel libpq-devel python3-devel python3-sphinx nodejs yarn rpm-build
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>pgAdmin 4</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.19.0</string>
|
||||
<string>4.20.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.19.0</string>
|
||||
<string>4.20.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION = 4.19.0.0
|
||||
VERSION = 4.20.0.0
|
||||
QMAKE_TARGET_COMPANY = "The pgAdmin Development Team"
|
||||
QMAKE_TARGET_PRODUCT = "pgAdmin 4"
|
||||
QMAKE_TARGET_DESCRIPTION = "pgAdmin 4 Desktop Runtime"
|
||||
|
||||
@@ -102,6 +102,11 @@ def get_chrome_version(args):
|
||||
print('The specified Chrome executable output an unexpected '
|
||||
'version string: {}.'.format(version_str))
|
||||
sys.exit(1)
|
||||
# On some linux distro `chrome--version` gives output like
|
||||
# 'Google Chrome 80.0.3987.132 unknown\n'
|
||||
# so we need to check and remove the unknown string from the version
|
||||
if version_str.endswith("unknown\n"):
|
||||
version_str = version_str.strip("unknown\n").strip()
|
||||
|
||||
chrome_version = '.'.join(version_str.split()[-1].split('.')[:-1])
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ indent_size = 2
|
||||
[*.css]
|
||||
indent_size = 2
|
||||
|
||||
[*.scss]
|
||||
indent_size = 2
|
||||
|
||||
# Matches the exact file package.json
|
||||
[{package.json}]
|
||||
indent_size = 2
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@ APP_ICON = 'pg-icon'
|
||||
|
||||
# Application version number components
|
||||
APP_RELEASE = 4
|
||||
APP_REVISION = 19
|
||||
APP_REVISION = 20
|
||||
|
||||
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
|
||||
# for GA releases.
|
||||
@@ -60,7 +60,7 @@ APP_SUFFIX = ''
|
||||
# Numeric application version for upgrade checks. Should be in the format:
|
||||
# [X]XYYZZ, where X is the release version, Y is the revision, with a leading
|
||||
# zero if needed, and Z represents the suffix, with a leading zero if needed
|
||||
APP_VERSION_INT = 41900
|
||||
APP_VERSION_INT = 42000
|
||||
|
||||
# DO NOT CHANGE!
|
||||
# The application version string, constructed from the components
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
define(
|
||||
['jquery', 'alertify', 'sources/pgadmin', 'sources/gettext',
|
||||
'sources/url_for',
|
||||
'sources/url_for','sources/utils',
|
||||
],
|
||||
function($, alertify, pgAdmin, gettext, url_for) {
|
||||
function($, alertify, pgAdmin, gettext, url_for, commonUtils) {
|
||||
pgAdmin = pgAdmin || window.pgAdmin || {};
|
||||
|
||||
/* Return back, this has been called more than once */
|
||||
@@ -43,8 +43,16 @@ define(
|
||||
build: function() {
|
||||
alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
hooks:{
|
||||
onshow:function(){
|
||||
var container = $(this.elements.footer).find('button:not([disabled])');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
},
|
||||
},
|
||||
|
||||
prepare:function() {
|
||||
this.setContent(this.message);
|
||||
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1266,13 +1266,14 @@ class ServerNode(PGChildNodeView):
|
||||
data={
|
||||
'status': 1,
|
||||
'result': gettext(
|
||||
'Named restore point created: {0}'.format(
|
||||
restore_point_name))
|
||||
'Named restore point created: {0}').format(
|
||||
restore_point_name)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(
|
||||
'Named restore point creation failed ({0})'.format(str(e))
|
||||
current_app.logger.error(gettext(
|
||||
'Named restore point creation failed ({0})').format(
|
||||
str(e))
|
||||
)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class CastModule(CollectionNodeModule):
|
||||
"""
|
||||
|
||||
NODE_TYPE = 'cast'
|
||||
COLLECTION_LABEL = 'Casts'
|
||||
COLLECTION_LABEL = gettext('Casts')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CastModule, self).__init__(*args, **kwargs)
|
||||
|
||||
+7
-7
@@ -111,10 +111,10 @@ define('pgadmin.node.event_trigger', [
|
||||
id: 'enabled', label: gettext('Trigger enabled?'),
|
||||
group: gettext('Definition'), mode: ['properties', 'edit','create'],
|
||||
options: [
|
||||
{label: 'Enable', value: 'O'},
|
||||
{label: 'Disable', value: 'D'},
|
||||
{label: 'Replica', value: 'R'},
|
||||
{label: 'Always', value: 'A'},
|
||||
{label: gettext('Enable'), value: 'O'},
|
||||
{label: gettext('Disable'), value: 'D'},
|
||||
{label: gettext('Replica'), value: 'R'},
|
||||
{label: gettext('Always'), value: 'A'},
|
||||
],
|
||||
control: 'select2', select2: { allowClear: false, width: '100%' },
|
||||
},{
|
||||
@@ -125,9 +125,9 @@ define('pgadmin.node.event_trigger', [
|
||||
id: 'eventname', label: gettext('Event'),
|
||||
group: gettext('Definition'), cell: 'string',
|
||||
options: [
|
||||
{label: 'DDL COMMAND START', value: 'DDL_COMMAND_START'},
|
||||
{label: 'DDL COMMAND END', value: 'DDL_COMMAND_END'},
|
||||
{label: 'SQL DROP', value: 'SQL_DROP'},
|
||||
{label: gettext('DDL COMMAND START'), value: 'DDL_COMMAND_START'},
|
||||
{label: gettext('DDL COMMAND END'), value: 'DDL_COMMAND_END'},
|
||||
{label: gettext('SQL DROP'), value: 'SQL_DROP'},
|
||||
],
|
||||
control: 'select2', select2: { allowClear: false, width: '100%' },
|
||||
},{
|
||||
|
||||
@@ -52,8 +52,8 @@ class Properties:
|
||||
execute_on_text = self.translate_execute_on_text(execute_on)
|
||||
response = dict(
|
||||
name=table_information_result['name'],
|
||||
type=gettext('readable' if not table_information_result[
|
||||
'writable'] else 'writable'),
|
||||
type=gettext('readable') if not table_information_result[
|
||||
'writable'] else gettext('writable'),
|
||||
format_type=table_information_result['pg_encoding_to_char'],
|
||||
format_options=table_information_result['fmtopts'],
|
||||
external_options=table_information_result['options'],
|
||||
@@ -65,14 +65,14 @@ class Properties:
|
||||
@staticmethod
|
||||
def translate_execute_on_text(execute_on):
|
||||
if execute_on['type'] == 'host':
|
||||
return 'host %s' % execute_on['value']
|
||||
return gettext('host %s') % execute_on['value']
|
||||
elif execute_on['type'] == 'per_host':
|
||||
return 'per host'
|
||||
return gettext('per host')
|
||||
elif execute_on['type'] == 'master_only':
|
||||
return 'master segment'
|
||||
return gettext('master segment')
|
||||
elif execute_on['type'] == 'all_segments':
|
||||
return 'all segments'
|
||||
return gettext('all segments')
|
||||
elif execute_on['type'] == 'segment':
|
||||
return '%s segment' % execute_on['value']
|
||||
return gettext('%s segment') % execute_on['value']
|
||||
elif execute_on['type'] == 'segments':
|
||||
return '%d segments' % execute_on['value']
|
||||
return gettext('%d segments') % execute_on['value']
|
||||
@@ -501,7 +501,7 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, coid=None):
|
||||
def delete(self, gid, sid, did, scid, coid=None, only_sql=False):
|
||||
"""
|
||||
This function will delete existing the collation object
|
||||
|
||||
@@ -511,6 +511,7 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
coid: Collation ID
|
||||
only_sql: Return only sql if True
|
||||
"""
|
||||
if coid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -548,6 +549,11 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
nspname=data['schema'],
|
||||
cascade=cascade,
|
||||
conn=self.conn)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return SQL
|
||||
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -685,7 +691,8 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return SQL.strip('\n'), data['name']
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, coid):
|
||||
def sql(self, gid, sid, did, scid, coid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will generates reverse engineered sql for collation
|
||||
object
|
||||
@@ -696,6 +703,8 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
coid: Collation ID
|
||||
diff_schema: Target Schema for schema diff
|
||||
json_resp: True then return json response
|
||||
"""
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
@@ -710,6 +719,9 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'create.sql']),
|
||||
data=data, conn=self.conn)
|
||||
@@ -722,6 +734,9 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
nspname=data['schema'])
|
||||
SQL = sql_header + '\n\n' + SQL.strip('\n')
|
||||
|
||||
if not json_resp:
|
||||
return SQL
|
||||
|
||||
return ajax_response(response=SQL)
|
||||
|
||||
@check_precondition
|
||||
@@ -793,5 +808,38 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the collation
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, data=data, scid=scid,
|
||||
coid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, coid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, coid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, coid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, CollationView)
|
||||
CollationView.register_node_view(blueprint)
|
||||
+18
@@ -1,5 +1,23 @@
|
||||
{% if data %}
|
||||
{# Change object's owner #}
|
||||
{% if (data.lc_collate and data.lc_type) or data.locale or data.copy_collation %}
|
||||
-- WARNING:
|
||||
-- We have found the difference in either of LC_COLLATE or LC_CTYPE or LOCALE,
|
||||
-- so we need to drop the existing collation first and re-create it.
|
||||
DROP COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }};
|
||||
|
||||
CREATE COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }}
|
||||
{% if data.lc_collate and data.lc_type %}
|
||||
(LC_COLLATE = {{ data.lc_collate|qtLiteral }}, LC_CTYPE = {{ data.lc_type|qtLiteral }});
|
||||
{% endif %}
|
||||
{% if data.locale %}
|
||||
(LOCALE = {{ data.locale|qtLiteral }});
|
||||
{% endif %}
|
||||
{% if data.copy_collation %}
|
||||
FROM {{ data.copy_collation }};
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if data.owner and data.owner != o_data.owner %}
|
||||
ALTER COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }}
|
||||
OWNER TO {{ conn|qtIdent(data.owner) }};
|
||||
|
||||
@@ -179,6 +179,8 @@ class DomainView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
'compare': [{'get': 'compare'}, {'get': 'compare'}]
|
||||
})
|
||||
|
||||
keys_to_ignore = ['oid', 'basensp', 'conoid', 'nspname', 'oid-2']
|
||||
|
||||
def validate_request(f):
|
||||
"""
|
||||
Works as a decorator.
|
||||
@@ -584,7 +586,7 @@ AND relkind != 'c'))"""
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, doid=None):
|
||||
def delete(self, gid, sid, did, scid, doid=None, only_sql=False):
|
||||
"""
|
||||
Drops the Domain object.
|
||||
|
||||
@@ -594,6 +596,7 @@ AND relkind != 'c'))"""
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
only_sql: Return only sql if True
|
||||
"""
|
||||
if doid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -602,7 +605,7 @@ AND relkind != 'c'))"""
|
||||
else:
|
||||
data = {'ids': [doid]}
|
||||
|
||||
if self.cmd == 'delete':
|
||||
if self.cmd == 'delete' or only_sql:
|
||||
# This is a cascade operation
|
||||
cascade = True
|
||||
else:
|
||||
@@ -634,6 +637,11 @@ AND relkind != 'c'))"""
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'delete.sql']),
|
||||
name=name, basensp=basensp, cascade=cascade)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return SQL
|
||||
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -684,7 +692,8 @@ AND relkind != 'c'))"""
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, doid=None, return_ajax_response=True):
|
||||
def sql(self, gid, sid, did, scid, doid=None, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
Returns the SQL for the Domain object.
|
||||
|
||||
@@ -694,7 +703,8 @@ AND relkind != 'c'))"""
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
return_ajax_response:
|
||||
diff_schema: Target Schema for schema diff
|
||||
json_resp: True then return json response
|
||||
"""
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
@@ -710,6 +720,9 @@ AND relkind != 'c'))"""
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
if diff_schema:
|
||||
data['basensp'] = diff_schema
|
||||
|
||||
# Get Type Length and Precision
|
||||
data.update(self._parse_type(data['fulltype']))
|
||||
|
||||
@@ -737,7 +750,7 @@ AND relkind != 'c'))"""
|
||||
""".format(self.qtIdent(self.conn, data['basensp'], data['name']))
|
||||
SQL = sql_header + SQL
|
||||
|
||||
if not return_ajax_response:
|
||||
if not json_resp:
|
||||
return SQL.strip('\n')
|
||||
|
||||
return ajax_response(response=SQL.strip('\n'))
|
||||
@@ -780,7 +793,7 @@ AND relkind != 'c'))"""
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
def get_sql(self, gid, sid, data, scid, doid=None):
|
||||
def get_sql(self, gid, sid, data, scid, doid=None, is_schema_diff=False):
|
||||
"""
|
||||
Generates the SQL statements to create/update the Domain.
|
||||
|
||||
@@ -790,6 +803,7 @@ AND relkind != 'c'))"""
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
is_schema_diff: True is function gets called from schema diff
|
||||
"""
|
||||
|
||||
if doid is not None:
|
||||
@@ -821,9 +835,19 @@ AND relkind != 'c'))"""
|
||||
|
||||
old_data['constraints'] = con_data
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data)
|
||||
# If fulltype or basetype or collname is changed while comparing
|
||||
# two schemas then we need to drop domain and recreate it
|
||||
if 'fulltype' in data or 'basetype' in data or 'collname' in data:
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'domain_schema_diff.sql']),
|
||||
data=data, o_data=old_data)
|
||||
else:
|
||||
if is_schema_diff:
|
||||
data['is_schema_diff'] = True
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data)
|
||||
return SQL.strip('\n'), data['name'] if 'name' in data else \
|
||||
old_data['name']
|
||||
else:
|
||||
@@ -892,18 +916,43 @@ AND relkind != 'c'))"""
|
||||
status, data = self._fetch_properties(did, scid, row['oid'])
|
||||
|
||||
if status:
|
||||
if 'constraints' in data and len(data['constraints']) > 0:
|
||||
for item in data['constraints']:
|
||||
# Remove keys that should not be the part
|
||||
# of comparision.
|
||||
if 'conoid' in item:
|
||||
item.pop('conoid')
|
||||
if 'nspname' in item:
|
||||
item.pop('nspname')
|
||||
|
||||
res[row['name']] = data
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the domains
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, scid=scid,
|
||||
data=data, doid=oid,
|
||||
is_schema_diff=True)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, doid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, doid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, doid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, DomainView)
|
||||
DomainView.register_node_view(blueprint)
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{% import 'macros/schemas/security.macros' as SECLABEL %}
|
||||
|
||||
-- WARNING:
|
||||
-- We have found the difference in either of datatype or collation,
|
||||
-- so we need to drop the existing domain first and re-create it.
|
||||
DROP DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }};
|
||||
|
||||
CREATE DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
AS {% if data.fulltype %}{{ data.fulltype }}{% else %}{{ o_data.fulltype }}{% endif %}{% if data.collname and data.collname != "pg_catalog.\"default\"" %}
|
||||
|
||||
COLLATE {{ data.collname }}{% endif %}{% if data.typdefault %}
|
||||
|
||||
DEFAULT {{ data.typdefault }}{% endif %}{% if data.typnotnull %}
|
||||
|
||||
NOT NULL{% endif %};
|
||||
|
||||
{% if data.owner %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }};
|
||||
{% endif %}
|
||||
{% if data.constraints %}
|
||||
{% for c in data.constraints.added %}{% if c.conname and c.consrc %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% endif -%};
|
||||
{% endfor -%}
|
||||
{% for c in data.constraints.changed %}{% if c.conname and c.consrc %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% endif -%};
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
IS '{{ data.description }}';{% endif -%}
|
||||
|
||||
{% if data.seclabels %}
|
||||
{% for r in data.seclabels %}
|
||||
{% if r.label and r.provider %}
|
||||
|
||||
|
||||
{{ SECLABEL.SET(conn, 'DOMAIN', data.name, r.provider, r.label, data.basensp) }}{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
+15
-1
@@ -20,7 +20,7 @@ ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET DEFAULT {{ data.typdefault }};
|
||||
{% elif data.typdefault == '' and o_data.typdefault %}
|
||||
{% elif (data.typdefault == '' or data.typdefault == None) and data.typdefault != o_data.typdefault %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP DEFAULT;
|
||||
@@ -34,6 +34,19 @@ ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(o_data['constraints'][c.conoid]['conname']) }};
|
||||
{% endfor -%}
|
||||
{% if data.is_schema_diff is defined and data.is_schema_diff %}
|
||||
{% for c in data.constraints.changed %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(c.conname) }};
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% if c.connoinherit %} NO INHERIT{% endif -%};
|
||||
|
||||
{% if c.description is defined and c.description != '' %}
|
||||
COMMENT ON CONSTRAINT {{ conn|qtIdent(c.conname) }} ON DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
IS {{ c.description|qtLiteral }};{% endif %}
|
||||
{% endfor -%}
|
||||
{% else %}
|
||||
{% for c in data.constraints.changed %}
|
||||
{% if c.conname and c.conname !=o_data['constraints'][c.conoid]['conname'] %}
|
||||
|
||||
@@ -46,6 +59,7 @@ ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
VALIDATE CONSTRAINT {{ conn|qtIdent(c.conname) }};
|
||||
{% endif %}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
{% for c in data.constraints.added %}
|
||||
{% if c.conname and c.consrc %}
|
||||
|
||||
|
||||
+1
-1
@@ -15,6 +15,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO postgres;
|
||||
+1
-1
@@ -1 +1 @@
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
+1
-1
@@ -14,6 +14,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO postgres;
|
||||
-4
@@ -144,10 +144,6 @@
|
||||
"grantee":"PUBLIC",
|
||||
"grantor":"postgres",
|
||||
"privileges":[{
|
||||
"privilege_type":"a",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
},{
|
||||
"privilege_type":"r",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO postgres;
|
||||
+1
-1
@@ -1 +1 @@
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
+1
-1
@@ -17,6 +17,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO postgres;
|
||||
-4
@@ -158,10 +158,6 @@
|
||||
"grantee":"PUBLIC",
|
||||
"grantor":"postgres",
|
||||
"privileges":[{
|
||||
"privilege_type":"a",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
},{
|
||||
"privilege_type":"r",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
|
||||
+1
-1
@@ -16,6 +16,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO enterprisedb;
|
||||
+1
-1
@@ -1 +1 @@
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
+1
-1
@@ -15,6 +15,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO enterprisedb;
|
||||
-4
@@ -143,10 +143,6 @@
|
||||
"grantee":"PUBLIC",
|
||||
"grantor":"enterprisedb",
|
||||
"privileges":[{
|
||||
"privilege_type":"a",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
},{
|
||||
"privilege_type":"r",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO enterprisedb;
|
||||
+1
-1
@@ -1 +1 @@
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
+1
-1
@@ -17,6 +17,6 @@ ALTER FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
COMMENT ON FOREIGN TABLE public."FT1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Test Comment';
|
||||
|
||||
GRANT INSERT, SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
GRANT SELECT ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO PUBLIC;
|
||||
|
||||
GRANT ALL ON TABLE public."FT1_$%{}[]()&*^!@""'`\/#" TO enterprisedb;
|
||||
-4
@@ -158,10 +158,6 @@
|
||||
"grantee":"PUBLIC",
|
||||
"grantor":"enterprisedb",
|
||||
"privileges":[{
|
||||
"privilege_type":"a",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
},{
|
||||
"privilege_type":"r",
|
||||
"privilege":true,
|
||||
"with_grant":false
|
||||
|
||||
+62
-2
@@ -532,7 +532,7 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, cfgid=None):
|
||||
def delete(self, gid, sid, did, scid, cfgid=None, only_sql=False):
|
||||
"""
|
||||
This function will drop the FTS Configuration object
|
||||
:param gid: group id
|
||||
@@ -540,6 +540,7 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param cfgid: FTS Configuration id
|
||||
:param only_sql: Return only sql if True
|
||||
"""
|
||||
if cfgid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -587,6 +588,10 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
cascade=cascade
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return sql
|
||||
|
||||
status, res = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -869,7 +874,8 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, cfgid):
|
||||
def sql(self, gid, sid, did, scid, cfgid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will reverse generate sql for sql panel
|
||||
:param gid: group id
|
||||
@@ -877,6 +883,8 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param cfgid: FTS Configuration id
|
||||
:param diff_schema: Target Schema for schema diff
|
||||
:param json_resp: True then return json response
|
||||
"""
|
||||
try:
|
||||
sql = render_template(
|
||||
@@ -901,6 +909,25 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"FTS Configuration node.")
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if diff_schema:
|
||||
data = {'schema': scid}
|
||||
# Fetch schema name from schema oid
|
||||
sql = render_template("/".join([self.template_path,
|
||||
'schema.sql']),
|
||||
data=data,
|
||||
conn=self.conn,
|
||||
)
|
||||
|
||||
status, schema = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=schema)
|
||||
|
||||
res = res.replace(schema, diff_schema)
|
||||
|
||||
if not json_resp:
|
||||
return res
|
||||
|
||||
return ajax_response(response=res)
|
||||
|
||||
except Exception as e:
|
||||
@@ -970,5 +997,38 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the fts configuration
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
|
||||
data=data, cfgid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, cfgid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, cfgid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, cfgid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, FtsConfigurationView)
|
||||
FtsConfigurationView.register_node_view(blueprint)
|
||||
+1
-1
@@ -212,7 +212,7 @@ define('pgadmin.node.fts_configuration', [
|
||||
' </div>',
|
||||
' <div class="col-6" header="token"></div>',
|
||||
' <div class="col-2">',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> ></button>',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> ><span class="sr-only">Add Token</span></button>',
|
||||
' </div>',
|
||||
' </div>',
|
||||
' </div>',
|
||||
|
||||
+49
-2
@@ -527,7 +527,7 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, dcid=None):
|
||||
def delete(self, gid, sid, did, scid, dcid=None, only_sql=False):
|
||||
"""
|
||||
This function will drop the FTS Dictionary object
|
||||
:param gid: group id
|
||||
@@ -535,6 +535,7 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param dcid: FTS Dictionary id
|
||||
:param only_sql: Return only sql if True
|
||||
"""
|
||||
if dcid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -581,6 +582,10 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
cascade=cascade
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return sql
|
||||
|
||||
status, res = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -766,7 +771,8 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, dcid):
|
||||
def sql(self, gid, sid, did, scid, dcid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will reverse generate sql for sql panel
|
||||
:param gid: group id
|
||||
@@ -774,6 +780,8 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param dcid: FTS Dictionary id
|
||||
:param diff_schema: Target Schema for schema diff
|
||||
:param json_resp: True then return json response
|
||||
"""
|
||||
|
||||
sql = render_template(
|
||||
@@ -819,6 +827,9 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
# Replace schema oid with schema name
|
||||
res['rows'][0]['schema'] = schema
|
||||
|
||||
if diff_schema:
|
||||
res['rows'][0]['schema'] = diff_schema
|
||||
|
||||
sql = render_template("/".join([self.template_path, 'create.sql']),
|
||||
data=res['rows'][0],
|
||||
conn=self.conn, is_displaying=True)
|
||||
@@ -832,6 +843,9 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
sql = sql_header + sql
|
||||
|
||||
if not json_resp:
|
||||
return sql
|
||||
|
||||
return ajax_response(response=sql.strip('\n'))
|
||||
|
||||
@check_precondition
|
||||
@@ -897,5 +911,38 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the fts configuration
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
|
||||
data=data, dcid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, dcid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, dcid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, dcid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, FtsDictionaryView)
|
||||
FtsDictionaryView.register_node_view(blueprint)
|
||||
+62
-2
@@ -476,7 +476,7 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, pid=None):
|
||||
def delete(self, gid, sid, did, scid, pid=None, only_sql=False):
|
||||
"""
|
||||
This function will drop the fts_parser object
|
||||
:param gid: group id
|
||||
@@ -484,6 +484,7 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param pid: fts tempate id
|
||||
:param only_sql: Return only sql if True
|
||||
"""
|
||||
if pid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -530,6 +531,10 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
cascade=cascade
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return sql
|
||||
|
||||
status, res = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -813,7 +818,8 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, pid):
|
||||
def sql(self, gid, sid, did, scid, pid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will reverse generate sql for sql panel
|
||||
:param gid: group id
|
||||
@@ -821,6 +827,8 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param pid: fts tempate id
|
||||
:param diff_schema: Target Schema for schema diff
|
||||
:param json_resp: True then return json response
|
||||
"""
|
||||
try:
|
||||
sql = render_template(
|
||||
@@ -846,6 +854,25 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if diff_schema:
|
||||
data = {'schema': scid}
|
||||
# Fetch schema name from schema oid
|
||||
sql = render_template("/".join([self.template_path,
|
||||
'schema.sql']),
|
||||
data=data,
|
||||
conn=self.conn,
|
||||
)
|
||||
|
||||
status, schema = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=schema)
|
||||
|
||||
res = res.replace(schema, diff_schema)
|
||||
|
||||
if not json_resp:
|
||||
return res
|
||||
|
||||
return ajax_response(response=res)
|
||||
|
||||
except Exception as e:
|
||||
@@ -915,5 +942,38 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the fts configuration
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
|
||||
data=data, pid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, pid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, FtsParserView)
|
||||
FtsParserView.register_node_view(blueprint)
|
||||
+17
@@ -15,6 +15,23 @@ ALTER TEXT SEARCH PARSER {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data.n
|
||||
ALTER TEXT SEARCH PARSER {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}}
|
||||
SET SCHEMA {{data.schema}};
|
||||
{% endif %}
|
||||
{# Schema Diff SQL for FTS PARSER #}
|
||||
{% if data.prsstart or data.prstoken or data.prsend or data.prslextype or data.prsheadline %}
|
||||
-- WARNING:
|
||||
-- We have found the difference in either of START or GETTOKEN or END or
|
||||
-- LEXTYPES or HEADLINE, so we need to drop the existing parser first
|
||||
-- and re-create it.
|
||||
DROP TEXT SEARCH PARSER {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}};
|
||||
|
||||
CREATE TEXT SEARCH PARSER {{ conn|qtIdent(o_data.schema, name) }} (
|
||||
START = {% if data.prsstart is defined %}{{data.prsstart}}{% else %}{{o_data.prsstart}}{% endif %},
|
||||
GETTOKEN = {% if data.prstoken is defined %}{{data.prstoken}}{% else %}{{o_data.prstoken}}{% endif %},
|
||||
END = {% if data.prsend is defined %}{{data.prsend}}{% else %}{{o_data.prsend}}{% endif %},
|
||||
LEXTYPES = {% if data.prslextype is defined %}{{data.prslextype}}{% else %}{{o_data.prslextype}}{% endif %}{% if (data.prsheadline and data.prsheadline != '-') or (o_data.prsheadline and o_data.prsheadline != '-') %},
|
||||
HEADLINE = {% if data.prsheadline is defined %}{{data.prsheadline}}{% else %}{{o_data.prsheadline}}{% endif %}{% endif %}
|
||||
|
||||
);
|
||||
{% endif %}
|
||||
{% if "description" in data and data.description != o_data.description %}
|
||||
COMMENT ON TEXT SEARCH PARSER {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}}
|
||||
IS {{ data.description|qtLiteral }};
|
||||
|
||||
+62
-2
@@ -443,7 +443,7 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, tid=None):
|
||||
def delete(self, gid, sid, did, scid, tid=None, only_sql=False):
|
||||
"""
|
||||
This function will drop the fts_template object
|
||||
:param gid: group id
|
||||
@@ -451,6 +451,7 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param tid: fts tempate id
|
||||
:param only_sql: Return only sql if True
|
||||
"""
|
||||
if tid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -493,6 +494,10 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
cascade=cascade
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return sql
|
||||
|
||||
status, res = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -691,7 +696,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, tid):
|
||||
def sql(self, gid, sid, did, scid, tid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will reverse generate sql for sql panel
|
||||
:param gid: group id
|
||||
@@ -699,6 +705,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param did: database id
|
||||
:param scid: schema id
|
||||
:param tid: fts tempate id
|
||||
:param diff_schema: Target Schema for schema diff
|
||||
:param json_resp: True then return json response
|
||||
"""
|
||||
sql = render_template(
|
||||
"/".join([self.template_path, 'sql.sql']),
|
||||
@@ -721,6 +729,25 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
"FTS Template node.")
|
||||
)
|
||||
|
||||
# Used for schema diff tool
|
||||
if diff_schema:
|
||||
data = {'schema': scid}
|
||||
# Fetch schema name from schema oid
|
||||
sql = render_template("/".join([self.template_path,
|
||||
'schema.sql']),
|
||||
data=data,
|
||||
conn=self.conn,
|
||||
)
|
||||
|
||||
status, schema = self.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=schema)
|
||||
|
||||
res = res.replace(schema, diff_schema)
|
||||
|
||||
if not json_resp:
|
||||
return res
|
||||
|
||||
return ajax_response(response=res)
|
||||
|
||||
@check_precondition
|
||||
@@ -786,5 +813,38 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the fts configuration
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, did=did, scid=scid,
|
||||
data=data, tid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, tid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, FtsTemplateView)
|
||||
FtsTemplateView.register_node_view(blueprint)
|
||||
+15
@@ -15,6 +15,21 @@ ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(o_data
|
||||
ALTER TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}}
|
||||
SET SCHEMA {{conn|qtIdent(data.schema)}};
|
||||
{% endif %}
|
||||
{# Schema Diff SQL for FTS PARSER #}
|
||||
{% if data.tmplinit or data.tmpllexize %}
|
||||
-- WARNING:
|
||||
-- We have found the difference in either of INIT or LEXIZE,
|
||||
-- so we need to drop the existing template first and re-create it.
|
||||
DROP TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}};
|
||||
|
||||
CREATE TEXT SEARCH TEMPLATE {{ conn|qtIdent(o_data.schema, name) }} (
|
||||
{% if data.tmplinit and data.tmplinit != '-'%}
|
||||
INIT = {{data.tmplinit}},
|
||||
{% endif %}
|
||||
LEXIZE = {% if data.tmpllexize is defined %}{{data.tmpllexize}}{% else %}{{o_data.tmpllexize}}{% endif %}
|
||||
|
||||
);
|
||||
{% endif %}
|
||||
{% if 'description' in data and data.description != o_data.description %}
|
||||
COMMENT ON TEXT SEARCH TEMPLATE {{conn|qtIdent(o_data.schema)}}.{{conn|qtIdent(name)}}
|
||||
IS {{ data.description|qtLiteral }};
|
||||
|
||||
@@ -220,7 +220,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
})
|
||||
|
||||
keys_to_ignore = ['oid', 'proowner', 'typnsp', 'xmin', 'prokind',
|
||||
'proisagg', 'pronamespace', 'proargdefaults']
|
||||
'proisagg', 'pronamespace', 'proargdefaults',
|
||||
'prorettype', 'proallargtypes', 'proacl', 'oid-2']
|
||||
|
||||
@property
|
||||
def required_args(self):
|
||||
@@ -1125,7 +1126,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
SQL = re.sub('\n{2,}', '\n\n', SQL)
|
||||
return SQL
|
||||
|
||||
def _get_sql(self, gid, sid, did, scid, data, fnid=None, is_sql=False):
|
||||
def _get_sql(self, gid, sid, did, scid, data, fnid=None, is_sql=False,
|
||||
is_schema_diff=False):
|
||||
"""
|
||||
Generates the SQL statements to create/update the Function.
|
||||
|
||||
@@ -1239,8 +1241,11 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
for v in data['variables']['added']:
|
||||
chngd_variables[v['name']] = v['value']
|
||||
|
||||
for v in old_data['variables']:
|
||||
old_data['chngd_variables'][v['name']] = v['value']
|
||||
# In case of schema diff we don't want variables from
|
||||
# old data
|
||||
if not is_schema_diff:
|
||||
for v in old_data['variables']:
|
||||
old_data['chngd_variables'][v['name']] = v['value']
|
||||
|
||||
# Prepare final dict of new and old variables
|
||||
for name, val in old_data['chngd_variables'].items():
|
||||
@@ -1624,7 +1629,15 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
status, sql = self._get_sql(gid, sid, did, scid, data, oid)
|
||||
status, sql = self._get_sql(gid, sid, did, scid, data, oid, False,
|
||||
True)
|
||||
# Check if return type is changed then we need to drop the
|
||||
# function first and then recreate it.
|
||||
drop_fun_sql = ''
|
||||
if 'prorettypename' in data:
|
||||
drop_fun_sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, fnid=oid, only_sql=True)
|
||||
sql = drop_fun_sql + '\n' + sql
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -31,7 +32,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
|
||||
{% if 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0'%}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -31,7 +32,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
|
||||
{% if 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif %}
|
||||
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -28,7 +29,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -29,7 +30,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -31,7 +32,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
|
||||
{% if 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -27,7 +28,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -31,7 +32,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
|
||||
{% if 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif %}
|
||||
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -28,7 +29,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}}{% endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -29,7 +30,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -31,7 +32,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
|
||||
{% if 'proparallel' in data and data.proparallel %}PARALLEL {{ data.proparallel }}{% elif 'proparallel' not in data and o_data.proparallel %}PARALLEL {{ o_data.proparallel }}{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}} {%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
+3
-2
@@ -18,7 +18,8 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
)
|
||||
RETURNS {{ o_data.prorettypename }}
|
||||
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
|
||||
|
||||
{% if 'lanname' in data %}
|
||||
LANGUAGE {{ data.lanname|qtLiteral }} {% else %}
|
||||
LANGUAGE {{ o_data.lanname|qtLiteral }}
|
||||
@@ -27,7 +28,7 @@ CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if d
|
||||
{% if ('prosecdef' in data and data.prosecdef) or ('prosecdef' not in data and o_data.prosecdef) %} SECURITY DEFINER{% endif %}
|
||||
{% if ('proiswindow' in data and data.proiswindow) or ('proiswindow' not in data and o_data.proiswindow) %} WINDOW{% endif %}
|
||||
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows %}
|
||||
{% if data.procost %}COST {{data.procost}}{% elif o_data.procost %}COST {{o_data.procost}}{% endif %}{% if data.prorows and data.prorows != '0' %}
|
||||
|
||||
ROWS {{data.prorows}}{% elif data.prorows is not defined and o_data.prorows and o_data.prorows != '0' %} ROWS {{o_data.prorows}}{%endif -%}{% if data.merged_variables %}{% for v in data.merged_variables %}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
'dependent': [{'get': 'dependents'}]
|
||||
})
|
||||
|
||||
keys_to_ignore = ['oid', 'schema', 'xmin']
|
||||
keys_to_ignore = ['oid', 'schema', 'xmin', 'oid-2']
|
||||
|
||||
def check_precondition(action=None):
|
||||
"""
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
import simplejson as json
|
||||
import re
|
||||
import copy
|
||||
import random
|
||||
|
||||
import pgadmin.browser.server_groups.servers.databases as database
|
||||
from flask import render_template, request, jsonify, url_for, current_app
|
||||
@@ -25,11 +23,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||
from .utils import BaseTableView
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
|
||||
directory_diff
|
||||
from pgadmin.tools.schema_diff.model import SchemaDiffModel
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
constraints.foreign_key import utils as fkey_utils
|
||||
from .schema_diff_utils import SchemaDiffTableCompare
|
||||
@@ -1212,8 +1205,6 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True
|
||||
diff_schema = kwargs['diff_schema'] if 'diff_schema' in kwargs else\
|
||||
None
|
||||
schema_diff_table = kwargs['schema_diff_table'] if\
|
||||
'schema_diff_table' in kwargs else None
|
||||
|
||||
if diff_data:
|
||||
return self._fetch_sql(did, scid, tid, diff_data, json_resp)
|
||||
@@ -1239,24 +1230,8 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
|
||||
if schema_diff_table:
|
||||
data['orig_name'] = data['name']
|
||||
data['name'] = 'schema_diff_temp_{0}'.format(
|
||||
random.randint(1, 9999999))
|
||||
|
||||
sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
|
||||
self, did, scid, tid, main_sql, data, json_resp,
|
||||
diff_partition_sql=True)
|
||||
else:
|
||||
sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
|
||||
self, did, scid, tid, main_sql, data, json_resp)
|
||||
|
||||
if schema_diff_table:
|
||||
# If partition tables have different partitions
|
||||
sql += render_template(
|
||||
"/".join([self.table_template_path, 'schema_diff.sql']),
|
||||
conn=self.conn, data=data, partition_sql=partition_sql
|
||||
)
|
||||
sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
|
||||
self, did, scid, tid, main_sql, data, json_resp)
|
||||
|
||||
return sql
|
||||
|
||||
@@ -1625,7 +1600,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
return sql
|
||||
|
||||
@BaseTableView.check_precondition
|
||||
def fetch_tables(self, sid, did, scid, tid=None, keys_to_remove=None):
|
||||
def fetch_tables(self, sid, did, scid, tid=None):
|
||||
"""
|
||||
This function will fetch the list of all the tables
|
||||
and will be used by schema diff.
|
||||
@@ -1634,9 +1609,13 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
:param did: Database Id
|
||||
:param scid: Schema Id
|
||||
:param tid: Table Id
|
||||
:param keys_to_remove: Table columns to be removed from the dataset
|
||||
:return: Table dataset
|
||||
"""
|
||||
sub_modules = ['index', 'rule', 'trigger']
|
||||
if self.manager.server_type == 'ppas' and \
|
||||
self.manager.version >= 120000:
|
||||
sub_modules.append('compound_trigger')
|
||||
|
||||
if tid:
|
||||
status, data = self._fetch_properties(did, scid, tid)
|
||||
|
||||
@@ -1647,7 +1626,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
data = super(TableView, self).properties(
|
||||
0, sid, did, scid, tid, data, False
|
||||
)
|
||||
self.remove_keys_for_comparision(data, keys_to_remove)
|
||||
|
||||
return data
|
||||
|
||||
else:
|
||||
@@ -1667,7 +1646,17 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
0, sid, did, scid, row['oid'], data, False
|
||||
)
|
||||
|
||||
self.remove_keys_for_comparision(data, keys_to_remove)
|
||||
# Get sub module data of a specified table for object
|
||||
# comparison
|
||||
for module in sub_modules:
|
||||
module_view = SchemaDiffRegistry.get_node_view(module)
|
||||
if module_view.blueprint.server_type is None or \
|
||||
self.manager.server_type in \
|
||||
module_view.blueprint.server_type:
|
||||
sub_data = module_view.fetch_objects_to_compare(
|
||||
sid=sid, did=did, scid=scid, tid=row['oid'],
|
||||
oid=None)
|
||||
data[module] = sub_data
|
||||
res[row['name']] = data
|
||||
|
||||
return res
|
||||
|
||||
+54
-7
@@ -29,6 +29,8 @@ from pgadmin.utils import IS_PY2
|
||||
from pgadmin.utils.compile_template_name import compile_template_path
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.tools.schema_diff.directory_compare import directory_diff,\
|
||||
parce_acl
|
||||
|
||||
|
||||
# If we are in Python3
|
||||
@@ -252,7 +254,7 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
# Schema Diff: Keys to ignore while comparing
|
||||
keys_to_ignore = ['oid', 'xmin', 'nspname', 'tfunction',
|
||||
'tgrelid', 'tgfoid']
|
||||
'tgrelid', 'tgfoid', 'oid-2']
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
@@ -938,8 +940,7 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
return SQL
|
||||
|
||||
@check_precondition
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
|
||||
ignore_keys=False):
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None):
|
||||
"""
|
||||
This function will fetch the list of all the triggers for
|
||||
specified schema id.
|
||||
@@ -969,14 +970,60 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
for row in triggers['rows']:
|
||||
status, data = self._fetch_properties(tid, row['oid'])
|
||||
if status:
|
||||
if ignore_keys:
|
||||
for key in self.keys_to_ignore:
|
||||
if key in data:
|
||||
del data[key]
|
||||
res[row['name']] = data
|
||||
|
||||
return res
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function returns the DDL/DML statements based on the
|
||||
comparison status.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
src_params = kwargs.get('source_params')
|
||||
tgt_params = kwargs.get('target_params')
|
||||
source = kwargs.get('source')
|
||||
target = kwargs.get('target')
|
||||
target_schema = kwargs.get('target_schema')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
|
||||
diff = ''
|
||||
if comp_status == 'source_only':
|
||||
diff = self.get_sql_from_diff(gid=src_params['gid'],
|
||||
sid=src_params['sid'],
|
||||
did=src_params['did'],
|
||||
scid=src_params['scid'],
|
||||
tid=src_params['tid'],
|
||||
oid=source['oid'],
|
||||
diff_schema=target_schema)
|
||||
elif comp_status == 'target_only':
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
drop_sql=True)
|
||||
elif comp_status == 'different':
|
||||
diff_dict = directory_diff(
|
||||
source, target,
|
||||
ignore_keys=self.keys_to_ignore, difference={}
|
||||
)
|
||||
diff_dict.update(parce_acl(source, target))
|
||||
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
data=diff_dict)
|
||||
|
||||
return diff
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, CompoundTriggerView, 'table')
|
||||
CompoundTriggerView.register_node_view(blueprint)
|
||||
+1
-1
@@ -450,7 +450,7 @@ define('pgadmin.node.exclusion_constraint', [
|
||||
titleTmpl = _.template([
|
||||
'<div class="subnode-header">',
|
||||
' <label class="control-label pg-el-sm-10"><%-label%></label>',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> title="' + _('Add new row') + '"></button>',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> title="' + gettext('Add new row') + '"></button>',
|
||||
'</div>'].join('\n')),
|
||||
$gridBody =
|
||||
$('<div class=\'pgadmin-control-group backgrid form-group col-12 object subnode\'></div>').append(
|
||||
|
||||
+1
-1
@@ -378,7 +378,7 @@ define('pgadmin.node.foreign_key', [
|
||||
titleTmpl = _.template([
|
||||
'<div class="subnode-header">',
|
||||
' <label class="control-label pg-el-sm-10"><%-label%></label>',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> title="' + _('Add new row') + '"></button>',
|
||||
' <button class="btn btn-sm-sq btn-secondary add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> title="' + gettext('Add new row') + '"></button>',
|
||||
'</div>'].join('\n')),
|
||||
$gridBody =
|
||||
$('<div class=\'pgadmin-control-group backgrid form-group col-12 object subnode\'></div>').append(
|
||||
|
||||
+2
-2
@@ -82,10 +82,10 @@ def get_foreign_keys(conn, tid, fkid=None, template_path=None):
|
||||
coveringindex = search_coveringindex(conn, tid, cols)
|
||||
fk['coveringindex'] = coveringindex
|
||||
if coveringindex:
|
||||
fk['autoindex'] = True
|
||||
fk['autoindex'] = False
|
||||
fk['hasindex'] = True
|
||||
else:
|
||||
fk['autoindex'] = False
|
||||
fk['autoindex'] = True
|
||||
fk['hasindex'] = False
|
||||
|
||||
return True, result['rows']
|
||||
|
||||
+37
-67
@@ -26,9 +26,7 @@ from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils import IS_PY2
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
|
||||
directory_diff
|
||||
from pgadmin.tools.schema_diff.model import SchemaDiffModel
|
||||
from pgadmin.tools.schema_diff.directory_compare import directory_diff
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas. \
|
||||
tables.indexes import utils as index_utils
|
||||
@@ -235,8 +233,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
# Schema Diff: Keys to ignore while comparing
|
||||
keys_to_ignore = ['oid', 'relowner', 'schema',
|
||||
'indrelid', 'nspname'
|
||||
]
|
||||
'indrelid', 'nspname', 'oid-2']
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
@@ -830,11 +827,8 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
def get_sql_from_index_diff(self, sid, did, scid, tid, idx, data=None,
|
||||
diff_schema=None, drop_req=False):
|
||||
|
||||
tmp_idx = idx
|
||||
schema = ''
|
||||
sql = ''
|
||||
if data:
|
||||
schema = self.schema
|
||||
|
||||
data['schema'] = self.schema
|
||||
data['nspname'] = self.schema
|
||||
data['table'] = self.table
|
||||
@@ -987,8 +981,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
|
||||
ignore_keys=False):
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None):
|
||||
"""
|
||||
This function will fetch the list of all the indexes for
|
||||
specified schema id.
|
||||
@@ -996,6 +989,7 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
:param sid: Server Id
|
||||
:param did: Database Id
|
||||
:param scid: Schema Id
|
||||
:param oid: Index Id
|
||||
:return:
|
||||
"""
|
||||
|
||||
@@ -1013,10 +1007,6 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
status, data = self._fetch_properties(did, tid,
|
||||
row['oid'])
|
||||
if status:
|
||||
if ignore_keys:
|
||||
for key in self.keys_to_ignore:
|
||||
if key in data:
|
||||
del data[key]
|
||||
res[row['name']] = data
|
||||
else:
|
||||
status, data = self._fetch_properties(did, tid,
|
||||
@@ -1030,55 +1020,35 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function will compare index properties and
|
||||
return the difference of SQL
|
||||
This function returns the DDL/DML statements based on the
|
||||
comparison status.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
src_sid = kwargs.get('source_sid')
|
||||
src_did = kwargs.get('source_did')
|
||||
src_scid = kwargs.get('source_scid')
|
||||
src_tid = kwargs.get('source_tid')
|
||||
src_oid = kwargs.get('source_oid')
|
||||
tar_sid = kwargs.get('target_sid')
|
||||
tar_did = kwargs.get('target_did')
|
||||
tar_scid = kwargs.get('target_scid')
|
||||
tar_tid = kwargs.get('target_tid')
|
||||
tar_oid = kwargs.get('target_oid')
|
||||
src_params = kwargs.get('source_params')
|
||||
tgt_params = kwargs.get('target_params')
|
||||
source = kwargs.get('source')
|
||||
target = kwargs.get('target')
|
||||
target_schema = kwargs.get('target_schema')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
|
||||
source = ''
|
||||
target = ''
|
||||
diff = ''
|
||||
|
||||
status, target_schema = self.get_schema(tar_sid,
|
||||
tar_did,
|
||||
tar_scid
|
||||
)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=target_schema)
|
||||
|
||||
if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
|
||||
diff = self.get_sql_from_index_diff(sid=src_sid,
|
||||
did=src_did, scid=src_scid,
|
||||
tid=src_tid, idx=src_oid,
|
||||
if comp_status == 'source_only':
|
||||
diff = self.get_sql_from_index_diff(sid=src_params['sid'],
|
||||
did=src_params['did'],
|
||||
scid=src_params['scid'],
|
||||
tid=src_params['tid'],
|
||||
idx=source['oid'],
|
||||
diff_schema=target_schema)
|
||||
elif comp_status == 'target_only':
|
||||
diff = self.delete(gid=1, sid=tgt_params['sid'],
|
||||
did=tgt_params['did'], scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'], idx=target['oid'],
|
||||
only_sql=True)
|
||||
|
||||
elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
|
||||
diff = self.delete(gid=1, sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_tid,
|
||||
idx=tar_oid, only_sql=True)
|
||||
|
||||
else:
|
||||
source = self.fetch_objects_to_compare(sid=src_sid, did=src_did,
|
||||
scid=src_scid, tid=src_tid,
|
||||
oid=src_oid)
|
||||
target = self.fetch_objects_to_compare(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_tid,
|
||||
oid=tar_oid)
|
||||
|
||||
if not (source or target):
|
||||
return None
|
||||
|
||||
elif comp_status == 'different':
|
||||
diff_dict = directory_diff(
|
||||
source, target, ignore_keys=self.keys_to_ignore,
|
||||
difference={}
|
||||
@@ -1102,19 +1072,19 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
create_req = True
|
||||
|
||||
if create_req:
|
||||
diff = self.get_sql_from_index_diff(sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=tar_tid,
|
||||
idx=tar_oid,
|
||||
diff = self.get_sql_from_index_diff(sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
idx=target['oid'],
|
||||
diff_schema=target_schema,
|
||||
drop_req=True)
|
||||
else:
|
||||
diff = self.get_sql_from_index_diff(sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=tar_tid,
|
||||
idx=tar_oid,
|
||||
diff = self.get_sql_from_index_diff(sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
idx=target['oid'],
|
||||
data=diff_dict)
|
||||
|
||||
return diff
|
||||
|
||||
+62
-99
@@ -10,9 +10,10 @@
|
||||
""" Implements Partitions Node """
|
||||
|
||||
import re
|
||||
import random
|
||||
import simplejson as json
|
||||
import pgadmin.browser.server_groups.servers.databases.schemas as schema
|
||||
from flask import render_template, request
|
||||
from flask import render_template, request, current_app
|
||||
from flask_babelex import gettext
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
|
||||
import DataTypeReader, VacuumSettings
|
||||
@@ -21,13 +22,9 @@ from pgadmin.utils.ajax import internal_server_error, \
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.utils \
|
||||
import BaseTableView
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
from pgadmin.utils.ajax import make_json_response, precondition_required
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils.ajax import make_json_response
|
||||
from pgadmin.browser.utils import PGChildModule
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
|
||||
directory_diff
|
||||
from pgadmin.tools.schema_diff.model import SchemaDiffModel
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
|
||||
|
||||
@@ -226,7 +223,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
|
||||
# Schema Diff: Keys to ignore while comparing
|
||||
keys_to_ignore = ['oid', 'schema', 'vacuum_table',
|
||||
'vacuum_toast', 'edit_types']
|
||||
'vacuum_toast', 'edit_types', 'oid-2']
|
||||
|
||||
def get_children_nodes(self, manager, **kwargs):
|
||||
nodes = []
|
||||
@@ -464,58 +461,57 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
@BaseTableView.check_precondition
|
||||
def get_sql_from_diff(self, **kwargs):
|
||||
"""
|
||||
This function will create sql on the basis the difference of 2 tables
|
||||
This function is used to get the DDL/DML statements for
|
||||
partitions.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
data = dict()
|
||||
res = None
|
||||
sid = kwargs['sid']
|
||||
did = kwargs['did']
|
||||
scid = kwargs['scid']
|
||||
tid = kwargs['tid']
|
||||
ptid = kwargs['ptid']
|
||||
diff_data = kwargs['diff_data'] if 'diff_data' in kwargs else None
|
||||
json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True
|
||||
diff_schema = kwargs['diff_schema'] if 'diff_schema' in kwargs else\
|
||||
None
|
||||
|
||||
if diff_data:
|
||||
SQL = render_template("/".join([self.partition_template_path,
|
||||
'properties.sql']),
|
||||
did=did, scid=scid, tid=tid,
|
||||
ptid=ptid, datlastsysoid=self.datlastsysoid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
source_data = kwargs['source_data'] if 'source_data' in kwargs \
|
||||
else None
|
||||
target_data = kwargs['target_data'] if 'target_data' in kwargs \
|
||||
else None
|
||||
|
||||
SQL, name = self.get_sql(did, scid, ptid, diff_data, res)
|
||||
SQL = re.sub('\n{2,}', '\n\n', SQL)
|
||||
SQL = SQL.strip('\n')
|
||||
return SQL
|
||||
else:
|
||||
main_sql = []
|
||||
# Store the original name and create a temporary name for
|
||||
# the partitioned(base) table.
|
||||
target_data['orig_name'] = target_data['name']
|
||||
target_data['name'] = 'temp_partitioned_{0}'.format(
|
||||
random.randint(1, 9999999))
|
||||
# For PG/EPAS 11 and above when we copy the data from original
|
||||
# table to temporary table for schema diff, we will have to create
|
||||
# a default partition to prevent the data loss.
|
||||
target_data['default_partition_name'] = \
|
||||
target_data['orig_name'] + '_default'
|
||||
|
||||
SQL = render_template("/".join([self.partition_template_path,
|
||||
'properties.sql']),
|
||||
did=did, scid=scid, tid=tid,
|
||||
ptid=ptid, datlastsysoid=self.datlastsysoid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
# Copy the partition scheme from source to target.
|
||||
if 'partition_scheme' in source_data:
|
||||
target_data['partition_scheme'] = source_data['partition_scheme']
|
||||
|
||||
if len(res['rows']) == 0:
|
||||
return gone(gettext(
|
||||
"The specified partitioned table could not be found."))
|
||||
partition_data = dict()
|
||||
partition_data['name'] = target_data['name']
|
||||
partition_data['schema'] = target_data['schema']
|
||||
partition_data['partition_type'] = source_data['partition_type']
|
||||
partition_data['default_partition_header'] = \
|
||||
'-- Create a default partition to prevent the data loss.\n' \
|
||||
'-- It helps when none of the partitions of a relation\n' \
|
||||
'-- matches the inserted data.'
|
||||
|
||||
data = res['rows'][0]
|
||||
# Create temporary name for partitions
|
||||
for item in source_data['partitions']:
|
||||
item['temp_partition_name'] = 'partition_{0}'.format(
|
||||
random.randint(1, 9999999))
|
||||
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
data['parent_schema'] = diff_schema
|
||||
partition_data['partitions'] = source_data['partitions']
|
||||
|
||||
return BaseTableView.get_reverse_engineered_sql(self, did,
|
||||
scid, ptid,
|
||||
main_sql, data,
|
||||
False)
|
||||
partition_sql = self.get_partitions_sql(partition_data,
|
||||
schema_diff=True)
|
||||
|
||||
return render_template(
|
||||
"/".join([self.partition_template_path, 'partition_diff.sql']),
|
||||
conn=self.conn, data=target_data, partition_sql=partition_sql,
|
||||
partition_data=partition_data
|
||||
)
|
||||
|
||||
@BaseTableView.check_precondition
|
||||
def detach(self, gid, sid, did, scid, tid, ptid):
|
||||
@@ -775,58 +771,25 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings,
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function will compare index properties and
|
||||
return the difference of SQL
|
||||
This function returns the DDL/DML statements based on the
|
||||
comparison status.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
src_sid = kwargs.get('source_sid')
|
||||
src_did = kwargs.get('source_did')
|
||||
src_scid = kwargs.get('source_scid')
|
||||
src_tid = kwargs.get('source_tid')
|
||||
src_oid = kwargs.get('source_oid')
|
||||
tar_sid = kwargs.get('target_sid')
|
||||
tar_did = kwargs.get('target_did')
|
||||
tar_scid = kwargs.get('target_scid')
|
||||
tar_tid = kwargs.get('target_tid')
|
||||
tar_oid = kwargs.get('target_oid')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
tgt_params = kwargs.get('target_params')
|
||||
parent_source_data = kwargs.get('parent_source_data')
|
||||
parent_target_data = kwargs.get('parent_target_data')
|
||||
|
||||
source = ''
|
||||
target = ''
|
||||
diff = ''
|
||||
diff = self.get_sql_from_diff(sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
source_data=parent_source_data,
|
||||
target_data=parent_target_data)
|
||||
|
||||
status, target_schema = self.get_schema_for_schema_diff(tar_sid,
|
||||
tar_did,
|
||||
tar_scid
|
||||
)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=target_schema)
|
||||
|
||||
if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
|
||||
diff = self.get_sql_from_diff(sid=src_sid,
|
||||
did=src_did, scid=src_scid,
|
||||
tid=src_tid, ptid=src_oid,
|
||||
diff_schema=target_schema)
|
||||
|
||||
elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
|
||||
SQL = render_template("/".join([self.partition_template_path,
|
||||
'properties.sql']),
|
||||
did=did, scid=scid, tid=tid,
|
||||
ptid=ptid, datlastsysoid=self.datlastsysoid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.table_template_path, 'properties.sql']),
|
||||
did=tar_did, scid=tar_scid, tid=tar_oid,
|
||||
datlastsysoid=self.datlastsysoid
|
||||
)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if status:
|
||||
self.cmd = 'delete'
|
||||
diff = super(PartitionsView, self).get_delete_sql(res)
|
||||
self.cmd = None
|
||||
|
||||
return diff
|
||||
return diff + '\n'
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, PartitionsView, 'table')
|
||||
|
||||
+2
-2
@@ -71,12 +71,12 @@ function(
|
||||
// To enable/disable all triggers for the table
|
||||
name: 'enable_all_triggers', node: 'partition', module: this,
|
||||
applies: ['object', 'context'], callback: 'enable_triggers_on_table',
|
||||
category: 'Trigger(s)', priority: 4, label: gettext('Enable All'),
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Enable All'),
|
||||
icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable',
|
||||
},{
|
||||
name: 'disable_all_triggers', node: 'partition', module: this,
|
||||
applies: ['object', 'context'], callback: 'disable_triggers_on_table',
|
||||
category: 'Trigger(s)', priority: 4, label: gettext('Disable All'),
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Disable All'),
|
||||
icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable',
|
||||
},{
|
||||
name: 'reset_table_stats', node: 'partition', module: this,
|
||||
|
||||
+68
-8
@@ -28,6 +28,8 @@ from pgadmin.utils.compile_template_name import compile_template_path
|
||||
from pgadmin.utils import IS_PY2
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.tools.schema_diff.directory_compare import directory_diff,\
|
||||
parce_acl
|
||||
|
||||
# If we are in Python3
|
||||
if not IS_PY2:
|
||||
@@ -184,7 +186,7 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
})
|
||||
|
||||
# Schema Diff: Keys to ignore while comparing
|
||||
keys_to_ignore = ['oid', 'schema', 'definition']
|
||||
keys_to_ignore = ['oid', 'schema', 'definition', 'oid-2']
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
@@ -520,7 +522,8 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
|
||||
@check_precondition
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, tid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
source_schema=None, diff_schema=None,
|
||||
drop_sql=False):
|
||||
|
||||
if drop_sql:
|
||||
SQL = self.delete(gid=gid, sid=sid, did=did,
|
||||
@@ -541,6 +544,11 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
SQL = ''
|
||||
|
||||
if data:
|
||||
if source_schema:
|
||||
if 'statements' in data:
|
||||
# Replace the source schema with the target schema
|
||||
data['statements'] = data['statements'].replace(
|
||||
source_schema, diff_schema)
|
||||
old_data = res_data
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
@@ -548,6 +556,11 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
else:
|
||||
if diff_schema:
|
||||
if 'statements' in res_data:
|
||||
# Replace the source schema with the target schema
|
||||
res_data['statements'] = \
|
||||
res_data['statements'].replace(
|
||||
res_data['schema'], diff_schema)
|
||||
res_data['schema'] = diff_schema
|
||||
|
||||
SQL = render_template("/".join(
|
||||
@@ -595,8 +608,7 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
|
||||
ignore_keys=False):
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None):
|
||||
"""
|
||||
This function will fetch the list of all the rules for
|
||||
specified schema id.
|
||||
@@ -628,13 +640,61 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
for row in rules['rows']:
|
||||
status, data = self._fetch_properties(row['oid'])
|
||||
if status:
|
||||
if ignore_keys:
|
||||
for key in self.keys_to_ignore:
|
||||
if key in data:
|
||||
del data[key]
|
||||
res[row['name']] = data
|
||||
return res
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function returns the DDL/DML statements based on the
|
||||
comparison status.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
src_params = kwargs.get('source_params')
|
||||
tgt_params = kwargs.get('target_params')
|
||||
source = kwargs.get('source')
|
||||
target = kwargs.get('target')
|
||||
target_schema = kwargs.get('target_schema')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
|
||||
diff = ''
|
||||
if comp_status == 'source_only':
|
||||
diff = self.get_sql_from_diff(gid=src_params['gid'],
|
||||
sid=src_params['sid'],
|
||||
did=src_params['did'],
|
||||
scid=src_params['scid'],
|
||||
tid=src_params['tid'],
|
||||
oid=source['oid'],
|
||||
diff_schema=target_schema)
|
||||
elif comp_status == 'target_only':
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
drop_sql=True)
|
||||
elif comp_status == 'different':
|
||||
diff_dict = directory_diff(
|
||||
source, target,
|
||||
ignore_keys=self.keys_to_ignore, difference={}
|
||||
)
|
||||
diff_dict.update(parce_acl(source, target))
|
||||
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
source_schema=source['schema'],
|
||||
diff_schema=target_schema,
|
||||
data=diff_dict)
|
||||
|
||||
return diff
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, RuleView, 'table')
|
||||
RuleView.register_node_view(blueprint)
|
||||
+160
-337
@@ -11,365 +11,97 @@
|
||||
|
||||
import copy
|
||||
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils.ajax import internal_server_error
|
||||
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
|
||||
directory_diff
|
||||
from pgadmin.tools.schema_diff.model import SchemaDiffModel
|
||||
are_dictionaries_identical
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
|
||||
|
||||
class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
table_keys_to_ignore = ['oid', 'schema', 'edit_types', 'attnum',
|
||||
'col_type', 'references', 'reltuples', 'oid-2',
|
||||
'rows_cnt', 'seqrelid', 'atttypid', 'elemoid',
|
||||
'hastoasttable', 'relhassubclass']
|
||||
|
||||
keys_to_ignore = ['oid', 'schema', 'vacuum_table',
|
||||
'vacuum_toast', 'edit_types', 'attnum', 'col_type',
|
||||
'references', 'reltuples', 'rows_cnt']
|
||||
constraint_keys_to_ignore = ['relname', 'nspname', 'parent_tbl',
|
||||
'attrelid', 'adrelid', 'fknsp', 'confrelid',
|
||||
'references', 'refnsp', 'remote_schema',
|
||||
'conkey', 'indkey']
|
||||
|
||||
keys_to_ignore_ddl_comp = ['oid',
|
||||
'schema',
|
||||
'columns',
|
||||
'edit_types',
|
||||
'primary_key',
|
||||
'unique_constraint',
|
||||
'exclude_constraint',
|
||||
'check_constraint',
|
||||
'foreign_key',
|
||||
'reltuples',
|
||||
'rows_cnt'
|
||||
]
|
||||
trigger_keys_to_ignore = ['xmin', 'tgrelid', 'tgfoid', 'tfunction',
|
||||
'tgqual', 'tgconstraint']
|
||||
index_keys_to_ignore = ['relowner', 'indrelid']
|
||||
|
||||
keys_to_remove = {
|
||||
'columns': ['relname', 'nspname', 'parent_tbl', 'attrelid', 'adrelid'],
|
||||
'primary_key': ['oid'],
|
||||
'unique_constraint': ['oid'],
|
||||
'check_constraint': ['oid', 'nspname'],
|
||||
'foreign_key': ['oid', 'fknsp', 'confrelid'],
|
||||
'exclude_constraint': ['oid'],
|
||||
'partitions': ['oid'],
|
||||
}
|
||||
|
||||
keys_to_remove_ddl_comp = {
|
||||
'columns': ['relname', 'nspname', 'parent_tbl', 'attrelid', 'adrelid'],
|
||||
'check_constraint': ['nspname'],
|
||||
'foreign_key': ['fknsp', 'confrelid']
|
||||
}
|
||||
keys_to_ignore = table_keys_to_ignore + constraint_keys_to_ignore \
|
||||
+ trigger_keys_to_ignore + index_keys_to_ignore
|
||||
|
||||
def compare(self, **kwargs):
|
||||
"""
|
||||
This function is used to compare all the table objects
|
||||
from two different schemas.
|
||||
|
||||
:return: Comparison Dictionary
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
src_sid = kwargs.get('source_sid')
|
||||
src_did = kwargs.get('source_did')
|
||||
src_scid = kwargs.get('source_scid')
|
||||
tar_sid = kwargs.get('target_sid')
|
||||
tar_did = kwargs.get('target_did')
|
||||
tar_scid = kwargs.get('target_scid')
|
||||
sub_modules = ['index', 'rule', 'trigger']
|
||||
source_params = {'sid': kwargs.get('source_sid'),
|
||||
'did': kwargs.get('source_did'),
|
||||
'scid': kwargs.get('source_scid')}
|
||||
target_params = {'sid': kwargs.get('target_sid'),
|
||||
'did': kwargs.get('target_did'),
|
||||
'scid': kwargs.get('target_scid')}
|
||||
|
||||
source_tables = self.fetch_tables(sid=src_sid, did=src_did,
|
||||
scid=src_scid)
|
||||
status, target_schema = self.get_schema(**target_params)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=target_schema)
|
||||
|
||||
target_tables = self.fetch_tables(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid)
|
||||
|
||||
if self.manager.version >= 120000:
|
||||
sub_modules.append('compound_trigger')
|
||||
source_tables = self.fetch_tables(**source_params)
|
||||
target_tables = self.fetch_tables(**target_params)
|
||||
|
||||
# If both the dict have no items then return None.
|
||||
if not (source_tables or target_tables) or (
|
||||
len(source_tables) <= 0 and len(target_tables) <= 0):
|
||||
return None
|
||||
|
||||
src_server_type, tar_server_type = self.get_server_type(src_sid,
|
||||
tar_sid)
|
||||
for module in sub_modules:
|
||||
|
||||
module_view = SchemaDiffRegistry.get_node_view(
|
||||
module)
|
||||
|
||||
# Get sub module data for source tables
|
||||
if module_view.blueprint.server_type is None or \
|
||||
src_server_type in module_view.blueprint.server_type:
|
||||
for key, val in source_tables.items():
|
||||
source = module_view.fetch_objects_to_compare(
|
||||
sid=src_sid,
|
||||
did=src_did,
|
||||
scid=src_scid,
|
||||
tid=val['oid'],
|
||||
oid=None,
|
||||
ignore_keys=True
|
||||
)
|
||||
source_tables[key][module] = source
|
||||
|
||||
# Get sub module data for target tables
|
||||
if module_view.blueprint.server_type is None or \
|
||||
tar_server_type in module_view.blueprint.server_type:
|
||||
for key, val in target_tables.items():
|
||||
target = module_view.fetch_objects_to_compare(
|
||||
sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=val['oid'],
|
||||
oid=None,
|
||||
ignore_keys=True
|
||||
)
|
||||
target_tables[key][module] = target
|
||||
|
||||
return compare_dictionaries(source_tables, target_tables,
|
||||
return compare_dictionaries(self, source_params, target_params,
|
||||
target_schema, source_tables,
|
||||
target_tables,
|
||||
self.node_type,
|
||||
self.blueprint.COLLECTION_LABEL,
|
||||
self.keys_to_ignore)
|
||||
|
||||
@staticmethod
|
||||
def get_server_type(src_id, tar_id):
|
||||
"""Get server types of source and target servers."""
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
src_manager = driver.connection_manager(src_id)
|
||||
tar_manager = driver.connection_manager(tar_id)
|
||||
|
||||
return src_manager.server_type, tar_manager.server_type
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function will compare properties of 2 tables and
|
||||
return the source DDL, target DDL and Difference of them.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
source_params = {'sid': kwargs.get('source_sid'),
|
||||
'did': kwargs.get('source_did'),
|
||||
'scid': kwargs.get('source_scid'),
|
||||
'tid': kwargs.get('source_oid'),
|
||||
'json_resp': False
|
||||
}
|
||||
|
||||
src_sid = kwargs.get('source_sid')
|
||||
src_did = kwargs.get('source_did')
|
||||
src_scid = kwargs.get('source_scid')
|
||||
src_oid = kwargs.get('source_oid')
|
||||
tar_sid = kwargs.get('target_sid')
|
||||
tar_did = kwargs.get('target_did')
|
||||
tar_scid = kwargs.get('target_scid')
|
||||
tar_oid = kwargs.get('target_oid')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
generate_script = False
|
||||
target_params = {'sid': kwargs.get('target_sid'),
|
||||
'did': kwargs.get('target_did'),
|
||||
'scid': kwargs.get('target_scid'),
|
||||
'tid': kwargs.get('target_oid'),
|
||||
'json_resp': False
|
||||
}
|
||||
|
||||
if 'generate_script' in kwargs and kwargs['generate_script']:
|
||||
generate_script = True
|
||||
|
||||
source = ''
|
||||
target = ''
|
||||
diff = ''
|
||||
ignore_sub_modules = ['column', 'constraints']
|
||||
|
||||
src_server_type, tar_server_type = self.get_server_type(src_sid,
|
||||
tar_sid)
|
||||
|
||||
status, target_schema = self.get_schema(tar_sid,
|
||||
tar_did,
|
||||
tar_scid
|
||||
)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=target_schema)
|
||||
|
||||
if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
|
||||
if not generate_script:
|
||||
source = self.get_sql_from_table_diff(sid=src_sid,
|
||||
did=src_did,
|
||||
scid=src_scid,
|
||||
tid=src_oid,
|
||||
json_resp=False)
|
||||
diff = self.get_sql_from_table_diff(sid=src_sid, did=src_did,
|
||||
scid=src_scid, tid=src_oid,
|
||||
diff_schema=target_schema,
|
||||
json_resp=False)
|
||||
|
||||
elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
|
||||
if not generate_script:
|
||||
target = self.get_sql_from_table_diff(sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=tar_oid,
|
||||
json_resp=False)
|
||||
|
||||
diff = self.get_drop_sql(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_oid)
|
||||
|
||||
elif comp_status == SchemaDiffModel.COMPARISON_STATUS['different']:
|
||||
source = self.fetch_tables(
|
||||
sid=src_sid, did=src_did,
|
||||
scid=src_scid, tid=src_oid,
|
||||
keys_to_remove=self.keys_to_remove_ddl_comp
|
||||
)
|
||||
target = self.fetch_tables(
|
||||
sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_oid,
|
||||
keys_to_remove=self.keys_to_remove_ddl_comp
|
||||
)
|
||||
|
||||
if self.manager.version < 100000:
|
||||
ignore_sub_modules.append('partition')
|
||||
|
||||
if self.manager.version < 120000:
|
||||
ignore_sub_modules.append('compound_trigger')
|
||||
|
||||
# In case of error return None
|
||||
if not (source or target):
|
||||
return None
|
||||
|
||||
diff_dict = directory_diff(
|
||||
source, target, ignore_keys=self.keys_to_ignore_ddl_comp,
|
||||
difference={}
|
||||
)
|
||||
|
||||
# Column comparison
|
||||
col_diff = self.table_col_ddl_comp(source, target)
|
||||
diff_dict.update(col_diff)
|
||||
|
||||
# Constraint comparison
|
||||
pk_diff = self.constraint_ddl_comp(source, target, diff_dict)
|
||||
diff_dict.update(pk_diff)
|
||||
|
||||
diff_dict.update(self.parce_acl(source, target))
|
||||
|
||||
if not generate_script:
|
||||
source = self.get_sql_from_table_diff(sid=src_sid,
|
||||
did=src_did,
|
||||
scid=src_scid,
|
||||
tid=src_oid,
|
||||
json_resp=False)
|
||||
target = self.get_sql_from_table_diff(sid=tar_sid,
|
||||
did=tar_did,
|
||||
scid=tar_scid,
|
||||
tid=tar_oid,
|
||||
json_resp=False)
|
||||
diff = self.get_sql_from_table_diff(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_oid,
|
||||
diff_data=diff_dict,
|
||||
json_resp=False)
|
||||
|
||||
for module in self.blueprint.submodules:
|
||||
if module.NODE_TYPE not in ignore_sub_modules:
|
||||
module_view = SchemaDiffRegistry.get_node_view(
|
||||
module.NODE_TYPE)
|
||||
|
||||
if module_view.blueprint.server_type and (
|
||||
src_server_type not in
|
||||
module_view.blueprint.server_type and
|
||||
tar_server_type not in
|
||||
module_view.blueprint.server_type
|
||||
):
|
||||
continue
|
||||
|
||||
if module_view.blueprint.server_type and (
|
||||
(src_server_type in
|
||||
module_view.blueprint.server_type and
|
||||
tar_server_type not in
|
||||
module_view.blueprint.server_type) or (
|
||||
src_server_type not in
|
||||
module_view.blueprint.server_type and
|
||||
tar_server_type in
|
||||
module_view.blueprint.server_type)
|
||||
):
|
||||
continue
|
||||
|
||||
result = module_view.compare(
|
||||
source_sid=src_sid, source_did=src_did,
|
||||
source_scid=src_scid, source_tid=src_oid,
|
||||
target_sid=tar_sid, target_did=tar_did,
|
||||
target_scid=tar_scid, target_tid=tar_oid
|
||||
)
|
||||
if result and module.NODE_TYPE != 'partition':
|
||||
child_diff = ''
|
||||
for res in result:
|
||||
if res['status'] == \
|
||||
SchemaDiffModel.COMPARISON_STATUS[
|
||||
'different']:
|
||||
source_oid = res['source_oid']
|
||||
target_oid = res['target_oid']
|
||||
else:
|
||||
source_oid = res['oid']
|
||||
target_oid = res['oid']
|
||||
|
||||
if res['status'] != \
|
||||
SchemaDiffModel.COMPARISON_STATUS[
|
||||
'identical']:
|
||||
child_diff = module_view.ddl_compare(
|
||||
source_sid=src_sid, source_did=src_did,
|
||||
source_scid=src_scid,
|
||||
source_oid=source_oid,
|
||||
source_tid=src_oid, target_sid=tar_sid,
|
||||
target_did=tar_did, target_scid=tar_scid,
|
||||
target_tid=tar_oid, target_oid=target_oid,
|
||||
comp_status=res['status']
|
||||
|
||||
)
|
||||
if child_diff:
|
||||
diff += '\n' + child_diff
|
||||
elif result:
|
||||
# For partition module
|
||||
identical = False
|
||||
source_only = False
|
||||
target_only = False
|
||||
different = False
|
||||
for res in result:
|
||||
if res['status'] == \
|
||||
SchemaDiffModel.COMPARISON_STATUS[
|
||||
'identical']:
|
||||
identical = True
|
||||
elif res['status'] == \
|
||||
SchemaDiffModel.COMPARISON_STATUS[
|
||||
'source_only']:
|
||||
source_only = True
|
||||
elif res['status'] == \
|
||||
SchemaDiffModel.COMPARISON_STATUS[
|
||||
'target_only']:
|
||||
target_only = True
|
||||
else:
|
||||
different = True
|
||||
|
||||
if identical:
|
||||
pass
|
||||
elif (source_only or target_only) and not different:
|
||||
for res in result:
|
||||
source_oid = res['oid']
|
||||
target_oid = res['oid']
|
||||
|
||||
child_diff = module_view.ddl_compare(
|
||||
source_sid=src_sid, source_did=src_did,
|
||||
source_scid=src_scid,
|
||||
source_oid=source_oid,
|
||||
source_tid=src_oid, target_sid=tar_sid,
|
||||
target_did=tar_did, target_scid=tar_scid,
|
||||
target_tid=tar_oid, target_oid=target_oid,
|
||||
comp_status=res['status']
|
||||
|
||||
)
|
||||
if child_diff:
|
||||
diff += child_diff
|
||||
else:
|
||||
diff = self.get_sql_from_table_diff(
|
||||
sid=src_sid,
|
||||
did=src_did,
|
||||
scid=src_scid,
|
||||
tid=src_oid,
|
||||
diff_schema=target_schema,
|
||||
json_resp=False,
|
||||
schema_diff_table=True
|
||||
)
|
||||
else:
|
||||
source = self.get_sql_from_table_diff(sid=src_sid, did=src_did,
|
||||
scid=src_scid, tid=src_oid,
|
||||
json_resp=False)
|
||||
target = self.get_sql_from_table_diff(sid=tar_sid, did=tar_did,
|
||||
scid=tar_scid, tid=tar_oid,
|
||||
json_resp=False)
|
||||
source = self.get_sql_from_table_diff(**source_params)
|
||||
target = self.get_sql_from_table_diff(**target_params)
|
||||
|
||||
return {'source_ddl': source,
|
||||
'target_ddl': target,
|
||||
'diff_ddl': diff
|
||||
'diff_ddl': ''
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def table_col_ddl_comp(source, target):
|
||||
def table_col_comp(source, target):
|
||||
"""
|
||||
Table Column comparison
|
||||
:param source: Source columns
|
||||
@@ -413,17 +145,14 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
return different
|
||||
|
||||
@staticmethod
|
||||
def constraint_ddl_comp(source_table, target_table, diff_dict):
|
||||
def table_constraint_comp(source_table, target_table):
|
||||
"""
|
||||
Table Constraint DDL comparison
|
||||
:param source: Source Table
|
||||
:param target: Target Table
|
||||
:param source_table: Source Table
|
||||
:param target_table: Target Table
|
||||
:return: Difference of constraints
|
||||
"""
|
||||
different = {}
|
||||
non_editable_keys = {}
|
||||
columns_to_be_dropped = []
|
||||
|
||||
non_editable_keys = {'primary_key': ['col_count',
|
||||
'condeferrable',
|
||||
'condeffered',
|
||||
@@ -456,14 +185,16 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
if type(target_cols) is list and len(
|
||||
target_cols) > 0:
|
||||
tmp_src = copy.deepcopy(source)
|
||||
tmp_src.pop('oid')
|
||||
if 'oid' in tmp_src:
|
||||
tmp_src.pop('oid')
|
||||
tmp_tar = None
|
||||
tmp = None
|
||||
for item in target_cols:
|
||||
if item['name'] == source['name']:
|
||||
tmp_tar = copy.deepcopy(item)
|
||||
tmp = copy.deepcopy(item)
|
||||
tmp_tar.pop('oid')
|
||||
if 'oid' in tmp_tar:
|
||||
tmp_tar.pop('oid')
|
||||
if tmp_tar and tmp_src != tmp_tar:
|
||||
tmp_updated = copy.deepcopy(source)
|
||||
for key in non_editable_keys[constraint]:
|
||||
@@ -474,7 +205,8 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
tmp_updated = None
|
||||
break
|
||||
if tmp_updated:
|
||||
tmp_updated['oid'] = tmp['oid']
|
||||
if 'oid' in tmp:
|
||||
tmp_updated['oid'] = tmp['oid']
|
||||
updated.append(tmp_updated)
|
||||
target_cols.remove(tmp)
|
||||
elif tmp_tar and tmp_src == tmp_tar:
|
||||
@@ -492,18 +224,109 @@ class SchemaDiffTableCompare(SchemaDiffObjectCompare):
|
||||
|
||||
return different
|
||||
|
||||
def remove_keys_for_comparision(self, data, keys=None):
|
||||
def get_sql_from_submodule_diff(self, source_params, target_params,
|
||||
target_schema, source, target, diff_dict):
|
||||
"""
|
||||
This function is used to remove specific keys from data
|
||||
This function returns the DDL/DML statements of the
|
||||
submodules of table based on the comparison status.
|
||||
|
||||
:param source_params:
|
||||
:param target_params:
|
||||
:param target_schema:
|
||||
:param source:
|
||||
:param target:
|
||||
:param diff_dict:
|
||||
:return:
|
||||
"""
|
||||
# Get the difference result for source and target columns
|
||||
col_diff = self.table_col_comp(source, target)
|
||||
diff_dict.update(col_diff)
|
||||
|
||||
keys_to_remove = keys if keys else self.keys_to_remove
|
||||
# Get the difference result for source and target constraints
|
||||
pk_diff = self.table_constraint_comp(source, target)
|
||||
diff_dict.update(pk_diff)
|
||||
|
||||
for p_key, p_val in keys_to_remove.items():
|
||||
if p_key in data and data[p_key] is not None \
|
||||
and len(data[p_key]) > 0:
|
||||
for item in data[p_key]:
|
||||
# Remove keys that should not be the part of comparision.
|
||||
for key in p_val:
|
||||
if key in item:
|
||||
item.pop(key)
|
||||
# Get the difference DDL/DML statements for table
|
||||
target_params['diff_data'] = diff_dict
|
||||
diff = self.get_sql_from_table_diff(**target_params)
|
||||
|
||||
ignore_sub_modules = ['column', 'constraints']
|
||||
if self.manager.version < 100000:
|
||||
ignore_sub_modules.append('partition')
|
||||
if self.manager.server_type == 'pg' or self.manager.version < 120000:
|
||||
ignore_sub_modules.append('compound_trigger')
|
||||
|
||||
# Iterate through all the sub modules of the table
|
||||
for module in self.blueprint.submodules:
|
||||
if module.NODE_TYPE not in ignore_sub_modules:
|
||||
module_view = \
|
||||
SchemaDiffRegistry.get_node_view(module.NODE_TYPE)
|
||||
|
||||
if module.NODE_TYPE == 'partition' and \
|
||||
('is_partitioned' in source and source['is_partitioned'])\
|
||||
and ('is_partitioned' in target and
|
||||
target['is_partitioned']):
|
||||
target_ddl = module_view.ddl_compare(
|
||||
target_params=target_params,
|
||||
parent_source_data=source,
|
||||
parent_target_data=target
|
||||
)
|
||||
|
||||
diff += '\n' + target_ddl
|
||||
elif module.NODE_TYPE != 'partition':
|
||||
dict1 = copy.deepcopy(source[module.NODE_TYPE])
|
||||
dict2 = copy.deepcopy(target[module.NODE_TYPE])
|
||||
|
||||
# Find the duplicate keys in both the dictionaries
|
||||
dict1_keys = set(dict1.keys())
|
||||
dict2_keys = set(dict2.keys())
|
||||
intersect_keys = dict1_keys.intersection(dict2_keys)
|
||||
|
||||
# Keys that are available in source and missing in target.
|
||||
added = dict1_keys - dict2_keys
|
||||
for item in added:
|
||||
source_ddl = module_view.ddl_compare(
|
||||
source_params=source_params,
|
||||
target_params=target_params,
|
||||
source=dict1[item],
|
||||
target=None,
|
||||
target_schema=target_schema,
|
||||
comp_status='source_only'
|
||||
)
|
||||
|
||||
diff += '\n' + source_ddl
|
||||
|
||||
# Keys that are available in target and missing in source.
|
||||
removed = dict2_keys - dict1_keys
|
||||
for item in removed:
|
||||
target_ddl = module_view.ddl_compare(
|
||||
source_params=source_params,
|
||||
target_params=target_params,
|
||||
source=None,
|
||||
target=dict2[item],
|
||||
target_schema=target_schema,
|
||||
comp_status='target_only'
|
||||
)
|
||||
|
||||
diff += '\n' + target_ddl
|
||||
|
||||
# Keys that are available in both source and target.
|
||||
for key in intersect_keys:
|
||||
# Recursively Compare the two dictionary
|
||||
if not are_dictionaries_identical(
|
||||
dict1[key], dict2[key], self.keys_to_ignore):
|
||||
|
||||
diff_ddl = module_view.ddl_compare(
|
||||
source_params=source_params,
|
||||
target_params=target_params,
|
||||
source=dict1[key],
|
||||
target=dict2[key],
|
||||
target_schema=target_schema,
|
||||
comp_status='different',
|
||||
parent_source_data=source,
|
||||
parent_target_data=target
|
||||
)
|
||||
|
||||
diff += '\n' + diff_ddl
|
||||
|
||||
return diff
|
||||
+4
-4
@@ -82,23 +82,23 @@ define('pgadmin.node.table', [
|
||||
},{
|
||||
name: 'truncate_table', node: 'table', module: this,
|
||||
applies: ['object', 'context'], callback: 'truncate_table',
|
||||
category: 'Truncate', priority: 3, label: gettext('Truncate'),
|
||||
category: gettext('Truncate'), priority: 3, label: gettext('Truncate'),
|
||||
icon: 'fa fa-eraser', enable : 'canCreate',
|
||||
},{
|
||||
name: 'truncate_table_cascade', node: 'table', module: this,
|
||||
applies: ['object', 'context'], callback: 'truncate_table_cascade',
|
||||
category: 'Truncate', priority: 3, label: gettext('Truncate Cascade'),
|
||||
category: gettext('Truncate'), priority: 3, label: gettext('Truncate Cascade'),
|
||||
icon: 'fa fa-eraser', enable : 'canCreate',
|
||||
},{
|
||||
// To enable/disable all triggers for the table
|
||||
name: 'enable_all_triggers', node: 'table', module: this,
|
||||
applies: ['object', 'context'], callback: 'enable_triggers_on_table',
|
||||
category: 'Trigger(s)', priority: 4, label: gettext('Enable All'),
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Enable All'),
|
||||
icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable',
|
||||
},{
|
||||
name: 'disable_all_triggers', node: 'table', module: this,
|
||||
applies: ['object', 'context'], callback: 'disable_triggers_on_table',
|
||||
category: 'Trigger(s)', priority: 4, label: gettext('Disable All'),
|
||||
category: gettext('Trigger(s)'), priority: 4, label: gettext('Disable All'),
|
||||
icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable',
|
||||
},{
|
||||
name: 'reset_table_stats', node: 'table', module: this,
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
|
||||
{% endif %}
|
||||
{### Alter column type and collation ###}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname) or data.col_type_conversion is defined %}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
|
||||
-- WARNING:
|
||||
-- The SQL statement below would normally be used to alter the datatype for the {{o_data.name}} column, however,
|
||||
@@ -101,7 +101,7 @@ COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, o_data.name)}}
|
||||
|
||||
{% endif %}
|
||||
{### Update column variables ###}
|
||||
{% if 'attoptions' in data and data.attoptions and data.attoptions|length > 0 %}
|
||||
{% if 'attoptions' in data and data.attoptions != None and data.attoptions|length > 0 %}
|
||||
{% set variables = data.attoptions %}
|
||||
{% if 'deleted' in variables and variables.deleted|length > 0 %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
|
||||
+5
-4
@@ -6,17 +6,18 @@
|
||||
{% if data.name and data.name != o_data.name %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
RENAME {{conn|qtIdent(o_data.name)}} TO {{conn|qtIdent(data.name)}};
|
||||
|
||||
{% endif %}
|
||||
{### Alter column type and collation ###}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname) or data.col_type_conversion is defined %}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
|
||||
-- WARNING:
|
||||
-- The SQL statement below would normally be used to alter the datatype for the {{o_data.name}} column, however,
|
||||
-- the current datatype cannot be cast to the target datatype so this conversion cannot be made automatically.
|
||||
|
||||
{% endif %}
|
||||
{### Alter column type and collation ###}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %} ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
|
||||
COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};
|
||||
{% endif %}
|
||||
{### Alter column default value ###}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
|
||||
|
||||
{% endif %}
|
||||
{### Alter column type and collation ###}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
|
||||
{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname) or data.col_type_conversion is defined %}
|
||||
{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
|
||||
-- WARNING:
|
||||
-- The SQL statement below would normally be used to alter the datatype for the XXX column, however,
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE {{conn|qtIdent(data.schema, data.name)}} (
|
||||
LIKE {{conn|qtIdent(data.schema, data.orig_name)}} INCLUDING ALL
|
||||
) PARTITION BY {{ data.partition_scheme }};
|
||||
{{partition_sql}}
|
||||
INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
|
||||
{% if data.columns and data.columns|length > 0 %}
|
||||
{% for c in data.columns %} {{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
|
||||
SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
||||
FROM {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
{% if partition_data.partitions and partition_data.partitions|length > 0 %}
|
||||
{% for part in partition_data.partitions %}
|
||||
DROP TABLE IF EXISTS {{conn|qtIdent(data.schema, part.partition_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, part.temp_partition_name)}}
|
||||
RENAME TO {{conn|qtIdent(part.partition_name)}};
|
||||
|
||||
{% endfor %}{% endif %}
|
||||
DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RENAME TO {{data.orig_name}};
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
CREATE TABLE {{conn|qtIdent(data.schema, data.name)}} (
|
||||
LIKE {{conn|qtIdent(data.schema, data.orig_name)}} INCLUDING ALL
|
||||
) PARTITION BY {{ data.partition_scheme }};
|
||||
{{partition_sql}}{{partition_data.default_partition_header}}
|
||||
CREATE TABLE IF NOT EXISTS {{conn|qtIdent(data.schema, data.default_partition_name)}} PARTITION OF {{conn|qtIdent(data.schema, data.name)}} DEFAULT;
|
||||
|
||||
INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
|
||||
{% if data.columns and data.columns|length > 0 %}
|
||||
{% for c in data.columns %} {{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
|
||||
SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
||||
FROM {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
{% if partition_data.partitions and partition_data.partitions|length > 0 %}
|
||||
{% for part in partition_data.partitions %}
|
||||
DROP TABLE IF EXISTS {{conn|qtIdent(data.schema, part.partition_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, part.temp_partition_name)}}
|
||||
RENAME TO {{conn|qtIdent(part.partition_name)}};
|
||||
|
||||
{% endfor %}{% endif %}
|
||||
DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RENAME TO {{data.orig_name}};
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE {{conn|qtIdent(data.schema, data.name)}} (
|
||||
LIKE {{conn|qtIdent(data.schema, data.orig_name)}} INCLUDING ALL
|
||||
) PARTITION BY {{ data.partition_scheme }};
|
||||
{{partition_sql}}
|
||||
INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
|
||||
{% if data.columns and data.columns|length > 0 %}
|
||||
{% for c in data.columns %} {{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
|
||||
SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
||||
FROM {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
{% if partition_data.partitions and partition_data.partitions|length > 0 %}
|
||||
{% for part in partition_data.partitions %}
|
||||
DROP TABLE IF EXISTS {{conn|qtIdent(data.schema, part.partition_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, part.temp_partition_name)}}
|
||||
RENAME TO {{conn|qtIdent(part.partition_name)}};
|
||||
|
||||
{% endfor %}{% endif %}
|
||||
DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RENAME TO {{data.orig_name}};
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
CREATE TABLE {{conn|qtIdent(data.schema, data.name)}} (
|
||||
LIKE {{conn|qtIdent(data.schema, data.orig_name)}} INCLUDING ALL
|
||||
) PARTITION BY {{ data.partition_scheme }};
|
||||
{{partition_sql}}{{partition_data.default_partition_header}}
|
||||
CREATE TABLE IF NOT EXISTS {{conn|qtIdent(data.schema, data.default_partition_name)}} PARTITION OF {{conn|qtIdent(data.schema, data.name)}} DEFAULT;
|
||||
|
||||
INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
|
||||
{% if data.columns and data.columns|length > 0 %}
|
||||
{% for c in data.columns %} {{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
|
||||
SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
||||
FROM {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
{% if partition_data.partitions and partition_data.partitions|length > 0 %}
|
||||
{% for part in partition_data.partitions %}
|
||||
DROP TABLE IF EXISTS {{conn|qtIdent(data.schema, part.partition_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, part.temp_partition_name)}}
|
||||
RENAME TO {{conn|qtIdent(part.partition_name)}};
|
||||
|
||||
{% endfor %}{% endif %}
|
||||
DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RENAME TO {{data.orig_name}};
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
|
||||
{% if data.columns and data.columns|length > 0 %}
|
||||
{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
|
||||
SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
||||
FROM {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
|
||||
|
||||
{{partition_sql}}
|
||||
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RENAME TO {{conn|qtIdent(data.orig_name)}};
|
||||
+1
-1
@@ -56,7 +56,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
SET (FILLFACTOR={{data.fillfactor}});
|
||||
{% elif data.fillfactor == '' and data.fillfactor != o_data.fillfactor %}
|
||||
{% elif (data.fillfactor == '' or data.fillfactor == None) and data.fillfactor != o_data.fillfactor %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RESET (FILLFACTOR);
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
SET (FILLFACTOR={{data.fillfactor}});
|
||||
{% elif data.fillfactor == '' and data.fillfactor != o_data.fillfactor %}
|
||||
{% elif (data.fillfactor == '' or data.fillfactor == None) and data.fillfactor != o_data.fillfactor %}
|
||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||
RESET (FILLFACTOR);
|
||||
|
||||
|
||||
+18
-8
@@ -3,9 +3,13 @@ ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname,
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% endif %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined) and o_data.lanname == 'edbspl' and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires)) %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined or data.is_constraint_trigger is defined) and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires or data.is_constraint_trigger != o_data.is_constraint_trigger)) %}
|
||||
{% set or_flag = False %}
|
||||
{% if data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL' %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% else %}
|
||||
CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% endif %}
|
||||
{% if data.fires is defined %}{{data.fires}} {% else %}{{o_data.fires}} {% endif %}{% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
@@ -16,23 +20,29 @@ CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if o_data.tgdeferrable %}
|
||||
{% if data.tgdeferrable %}
|
||||
DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
|
||||
{% elif o_data.tgdeferrable %}
|
||||
DEFERRABLE{% if o_data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
|
||||
{% endif %}{% if data.is_row_trigger is not defined %}
|
||||
FOR EACH{% if o_data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% else %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% endif %}
|
||||
{% if o_data.whenclause %}
|
||||
|
||||
{% if data.whenclause %}
|
||||
WHEN {{ data.whenclause }}
|
||||
{% elif o_data.whenclause %}
|
||||
WHEN {{ o_data.whenclause }}
|
||||
{% endif %}
|
||||
|
||||
{% if (data.prosrc is not defined) %}
|
||||
{{ o_data.prosrc }};
|
||||
{% if (data.tfunction is defined) %}
|
||||
EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%};
|
||||
{% else %}
|
||||
{{ data.prosrc }};
|
||||
EXECUTE PROCEDURE {{ o_data.tfunction }}{% if o_data.tgargs %}({{ o_data.tgargs }}){% else %}(){% endif%};
|
||||
{% endif %}
|
||||
|
||||
{% if data.description is not defined and o_data.description %}
|
||||
|
||||
+23
-4
@@ -3,9 +3,13 @@ ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname,
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
|
||||
{% endif %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined) and o_data.lanname == 'edbspl' and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires)) %}
|
||||
{% if ((data.prosrc is defined or data.is_row_trigger is defined or data.evnt_insert is defined or data.evnt_delete is defined or data.evnt_update is defined or data.fires is defined or data.is_constraint_trigger is defined) and (o_data.prosrc != data.prosrc or data.is_row_trigger != o_data.is_row_trigger or data.evnt_insert != o_data.evnt_insert or data.evnt_delete != o_data.evnt_delete or data.evnt_update != o_data.evnt_update or o_data.fires != data.fires or data.is_constraint_trigger != o_data.is_constraint_trigger)) %}
|
||||
{% set or_flag = False %}
|
||||
{% if data.lanname == 'edbspl' or data.tfunction == 'Inline EDB-SPL' %}
|
||||
CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% else %}
|
||||
CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% endif %}
|
||||
{% if data.fires is defined %}{{data.fires}} {% else %}{{o_data.fires}} {% endif %}{% if data.evnt_insert is not defined %}{% if o_data.evnt_insert %}INSERT{% set or_flag = True %}
|
||||
{% endif %}{% else %}{% if data.evnt_insert %}INSERT{% set or_flag = True %}{% endif %}{% endif %}{% if data.evnt_delete is not defined %}{% if o_data.evnt_delete %}
|
||||
{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
|
||||
@@ -16,24 +20,39 @@ CREATE OR REPLACE TRIGGER {{ conn|qtIdent(data.name) }}
|
||||
{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}{%endif %}{% endif %}{% if data.evnt_update is not defined %}{% if o_data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}
|
||||
{% endif %}{% else %}{% if data.evnt_update %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if o_data.columns|length > 0 %}OF {% for c in o_data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c) }}{% endfor %}{% endif %}{% endif %}
|
||||
{% endif %}
|
||||
|
||||
ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||
{% if o_data.tgdeferrable %}
|
||||
{% if data.tgdeferrable %}
|
||||
DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
|
||||
{% elif o_data.tgdeferrable %}
|
||||
DEFERRABLE{% if o_data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
|
||||
|
||||
{% endif %}{% if data.is_row_trigger is not defined %}
|
||||
FOR EACH{% if o_data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% else %}
|
||||
FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %} {% endif %}
|
||||
{% if o_data.whenclause %}
|
||||
|
||||
{% if data.whenclause %}
|
||||
WHEN {{ data.whenclause }}
|
||||
{% elif o_data.whenclause %}
|
||||
WHEN {{ o_data.whenclause }}
|
||||
{% endif %}
|
||||
|
||||
{%if data.tfunction == 'Inline EDB-SPL' %}
|
||||
{% if (data.prosrc is not defined) %}
|
||||
{{ o_data.prosrc }};
|
||||
{% else %}
|
||||
{{ data.prosrc }};
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if (data.tfunction is defined) %}
|
||||
EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%};
|
||||
{% else %}
|
||||
EXECUTE PROCEDURE {{ o_data.tfunction }}{% if o_data.tgargs %}({{ o_data.tgargs }}){% else %}(){% endif%};
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if data.description is not defined and o_data.description %}
|
||||
COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
|
||||
+55
-8
@@ -29,6 +29,8 @@ from pgadmin.utils.compile_template_name import compile_template_path
|
||||
from pgadmin.utils import IS_PY2
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
from pgadmin.tools.schema_diff.directory_compare import directory_diff,\
|
||||
parce_acl
|
||||
|
||||
# If we are in Python3
|
||||
if not IS_PY2:
|
||||
@@ -249,7 +251,8 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
})
|
||||
|
||||
# Schema Diff: Keys to ignore while comparing
|
||||
keys_to_ignore = ['oid', 'xmin', 'nspname', 'tgrelid', 'tgfoid', 'prosrc']
|
||||
keys_to_ignore = ['oid', 'xmin', 'nspname', 'tgrelid', 'tgfoid', 'prosrc',
|
||||
'oid-2']
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
@@ -794,7 +797,7 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
SQL, name = trigger_utils.get_sql(
|
||||
self.conn, data, tid, oid,
|
||||
self.datlastsysoid,
|
||||
self.blueprint.show_system_objects)
|
||||
self.blueprint.show_system_objects, True)
|
||||
|
||||
if not isinstance(SQL, (str, unicode)):
|
||||
return SQL
|
||||
@@ -932,8 +935,7 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
|
||||
ignore_keys=False):
|
||||
def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None):
|
||||
"""
|
||||
This function will fetch the list of all the triggers for
|
||||
specified schema id.
|
||||
@@ -963,14 +965,59 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
||||
for row in triggers['rows']:
|
||||
status, data = self._fetch_properties(tid, row['oid'])
|
||||
if status:
|
||||
if ignore_keys:
|
||||
for key in self.keys_to_ignore:
|
||||
if key in data:
|
||||
del data[key]
|
||||
res[row['name']] = data
|
||||
|
||||
return res
|
||||
|
||||
def ddl_compare(self, **kwargs):
|
||||
"""
|
||||
This function returns the DDL/DML statements based on the
|
||||
comparison status.
|
||||
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
src_params = kwargs.get('source_params')
|
||||
tgt_params = kwargs.get('target_params')
|
||||
source = kwargs.get('source')
|
||||
target = kwargs.get('target')
|
||||
target_schema = kwargs.get('target_schema')
|
||||
comp_status = kwargs.get('comp_status')
|
||||
|
||||
diff = ''
|
||||
if comp_status == 'source_only':
|
||||
diff = self.get_sql_from_diff(gid=src_params['gid'],
|
||||
sid=src_params['sid'],
|
||||
did=src_params['did'],
|
||||
scid=src_params['scid'],
|
||||
tid=src_params['tid'],
|
||||
oid=source['oid'],
|
||||
diff_schema=target_schema)
|
||||
elif comp_status == 'target_only':
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
drop_sql=True)
|
||||
elif comp_status == 'different':
|
||||
diff_dict = directory_diff(
|
||||
source, target,
|
||||
ignore_keys=self.keys_to_ignore, difference={}
|
||||
)
|
||||
diff_dict.update(parce_acl(source, target))
|
||||
|
||||
diff = self.get_sql_from_diff(gid=tgt_params['gid'],
|
||||
sid=tgt_params['sid'],
|
||||
did=tgt_params['did'],
|
||||
scid=tgt_params['scid'],
|
||||
tid=tgt_params['tid'],
|
||||
oid=target['oid'],
|
||||
data=diff_dict)
|
||||
return diff
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, TriggerView, 'table')
|
||||
TriggerView.register_node_view(blueprint)
|
||||
+34
-1
@@ -141,7 +141,7 @@ def get_trigger_function_and_columns(conn, data, tid,
|
||||
|
||||
@get_template_path
|
||||
def get_sql(conn, data, tid, trid, datlastsysoid,
|
||||
show_system_objects, template_path=None):
|
||||
show_system_objects, is_schema_diff=False, template_path=None):
|
||||
"""
|
||||
This function will generate sql from model data.
|
||||
|
||||
@@ -151,6 +151,7 @@ def get_sql(conn, data, tid, trid, datlastsysoid,
|
||||
:param trid: Trigger ID
|
||||
:param datlastsysoid:
|
||||
:param show_system_objects: Show System Object value True or False
|
||||
:param is_schema_diff:
|
||||
:param template_path: Optional template path
|
||||
:return:
|
||||
"""
|
||||
@@ -173,6 +174,35 @@ def get_sql(conn, data, tid, trid, datlastsysoid,
|
||||
if 'name' not in data:
|
||||
name = data['name'] = old_data['name']
|
||||
|
||||
drop_sql = ''
|
||||
if is_schema_diff:
|
||||
if 'table' not in data:
|
||||
data['table'] = old_data['relname']
|
||||
if 'schema' not in data:
|
||||
data['schema'] = old_data['nspname']
|
||||
|
||||
# If any of the below key is present in data then we need to drop
|
||||
# trigger and re-create it.
|
||||
key_array = ['prosrc', 'is_row_trigger', 'evnt_insert',
|
||||
'evnt_delete', 'evnt_update', 'fires', 'tgdeferrable',
|
||||
'whenclause', 'tfunction', 'tgargs', 'columns',
|
||||
'is_constraint_trigger', 'tginitdeferred']
|
||||
|
||||
is_drop_trigger = False
|
||||
for key in key_array:
|
||||
if key in data:
|
||||
is_drop_trigger = True
|
||||
break
|
||||
|
||||
if is_drop_trigger:
|
||||
tmp_data = dict()
|
||||
tmp_data['name'] = data['name']
|
||||
tmp_data['nspname'] = old_data['nspname']
|
||||
tmp_data['relname'] = old_data['relname']
|
||||
drop_sql = render_template("/".join([template_path,
|
||||
'delete.sql']),
|
||||
data=tmp_data, conn=conn)
|
||||
|
||||
old_data = get_trigger_function_and_columns(
|
||||
conn, old_data, tid, show_system_objects)
|
||||
|
||||
@@ -182,6 +212,9 @@ def get_sql(conn, data, tid, trid, datlastsysoid,
|
||||
"/".join([template_path, 'update.sql']),
|
||||
data=data, o_data=old_data, conn=conn
|
||||
)
|
||||
|
||||
if is_schema_diff:
|
||||
SQL = drop_sql + '\n' + SQL
|
||||
else:
|
||||
required_args = {
|
||||
'name': 'Name',
|
||||
|
||||
@@ -588,6 +588,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
if not json_resp:
|
||||
display_comments = False
|
||||
res_data = parse_rule_definition(res)
|
||||
# Update the correct table name for rules
|
||||
if 'view' in res_data:
|
||||
res_data['view'] = table
|
||||
|
||||
rules_sql += render_template("/".join(
|
||||
[self.rules_template_path, 'create.sql']),
|
||||
data=res_data, display_comments=display_comments)
|
||||
@@ -1298,11 +1302,12 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
status=200
|
||||
)
|
||||
|
||||
def get_partitions_sql(self, partitions):
|
||||
def get_partitions_sql(self, partitions, schema_diff=False):
|
||||
"""
|
||||
This function will iterate all the partitions and create SQL.
|
||||
|
||||
:param partitions: List of partitions
|
||||
:param schema_diff: If true then create sql accordingly.
|
||||
"""
|
||||
sql = ''
|
||||
|
||||
@@ -1361,7 +1366,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
|
||||
# Check if partition is again declare as partitioned table.
|
||||
if 'is_sub_partitioned' in row and row['is_sub_partitioned']:
|
||||
part_data['partition_scheme'] = self.get_partition_scheme(row)
|
||||
part_data['partition_scheme'] = row['sub_partition_scheme'] \
|
||||
if 'sub_partition_scheme' in row else \
|
||||
self.get_partition_scheme(row)
|
||||
|
||||
part_data['is_partitioned'] = True
|
||||
|
||||
if 'is_attach' in row and row['is_attach']:
|
||||
@@ -1370,12 +1378,17 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||
data=part_data, conn=self.conn
|
||||
)
|
||||
else:
|
||||
# For schema diff we create temporary partitions to copy the
|
||||
# data from original table to temporary table.
|
||||
if schema_diff:
|
||||
part_data['name'] = row['temp_partition_name']
|
||||
|
||||
partition_sql = render_template(
|
||||
"/".join([self.partition_template_path, 'create.sql']),
|
||||
data=part_data, conn=self.conn
|
||||
)
|
||||
|
||||
sql += partition_sql + '\n'
|
||||
sql += partition_sql
|
||||
|
||||
return sql
|
||||
|
||||
|
||||
@@ -219,6 +219,9 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
{'get': 'get_external_functions_list'}]
|
||||
})
|
||||
|
||||
keys_to_ignore = ['oid', 'typnamespace', 'typrelid', 'typarray', 'alias',
|
||||
'schema', 'oid-2']
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
This function will behave as a decorator which will checks
|
||||
@@ -1071,7 +1074,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, tid=None):
|
||||
def delete(self, gid, sid, did, scid, tid=None, only_sql=False):
|
||||
"""
|
||||
This function will updates existing the type object
|
||||
|
||||
@@ -1081,6 +1084,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
tid: Type ID
|
||||
only_sql: Return only sql if True
|
||||
"""
|
||||
if tid is None:
|
||||
data = request.form if request.form else json.loads(
|
||||
@@ -1090,7 +1094,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
data = {'ids': [tid]}
|
||||
|
||||
# Below will decide if it's simple drop or drop with cascade call
|
||||
if self.cmd == 'delete':
|
||||
if self.cmd == 'delete' or only_sql:
|
||||
# This is a cascade operation
|
||||
cascade = True
|
||||
else:
|
||||
@@ -1128,6 +1132,11 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
data=data,
|
||||
cascade=cascade,
|
||||
conn=self.conn)
|
||||
|
||||
# Used for schema diff tool
|
||||
if only_sql:
|
||||
return SQL
|
||||
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -1279,10 +1288,19 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
old_data.update(self.additional_properties(old_data, tid))
|
||||
old_data = self._convert_for_sql(old_data)
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data, conn=self.conn
|
||||
)
|
||||
# If typname or collname is changed while comparing
|
||||
# two schemas then we need to drop type and recreate it
|
||||
if 'typtype' in data or 'typname' in data or 'collname' in data\
|
||||
or 'typinput' in data or 'typoutput' in data:
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'type_schema_diff.sql']),
|
||||
data=data, o_data=old_data, conn=self.conn
|
||||
)
|
||||
else:
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data, conn=self.conn
|
||||
)
|
||||
else:
|
||||
required_args = [
|
||||
'name',
|
||||
@@ -1331,7 +1349,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
return SQL, data['name'] if 'name' in data else old_data['name']
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, tid):
|
||||
def sql(self, gid, sid, did, scid, tid, diff_schema=None,
|
||||
json_resp=True):
|
||||
"""
|
||||
This function will generates reverse engineered sql for type object
|
||||
|
||||
@@ -1341,6 +1360,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
tid: Type ID
|
||||
diff_schema: Target Schema for schema diff
|
||||
json_resp: True then return json response
|
||||
"""
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path,
|
||||
@@ -1359,6 +1380,9 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
# Making copy of output for future use
|
||||
data = dict(res['rows'][0])
|
||||
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
|
||||
SQL = render_template("/".join([self.template_path, 'acl.sql']),
|
||||
scid=scid, tid=tid)
|
||||
status, acl = self.conn.execute_dict(SQL)
|
||||
@@ -1401,6 +1425,9 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
data=data, conn=self.conn)
|
||||
SQL = sql_header + '\n\n' + SQL
|
||||
|
||||
if not json_resp:
|
||||
return SQL.strip('\n')
|
||||
|
||||
return ajax_response(response=SQL)
|
||||
|
||||
@check_precondition
|
||||
@@ -1473,5 +1500,38 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
||||
|
||||
return res
|
||||
|
||||
def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
|
||||
diff_schema=None, drop_sql=False):
|
||||
"""
|
||||
This function is used to get the DDL/DML statements.
|
||||
:param gid: Group ID
|
||||
:param sid: Serve ID
|
||||
:param did: Database ID
|
||||
:param scid: Schema ID
|
||||
:param oid: Collation ID
|
||||
:param data: Difference data
|
||||
:param diff_schema: Target Schema
|
||||
:param drop_sql: True if need to drop the types
|
||||
:return:
|
||||
"""
|
||||
sql = ''
|
||||
if data:
|
||||
if diff_schema:
|
||||
data['schema'] = diff_schema
|
||||
sql, name = self.get_sql(gid=gid, sid=sid, scid=scid,
|
||||
data=data, tid=oid)
|
||||
else:
|
||||
if drop_sql:
|
||||
sql = self.delete(gid=gid, sid=sid, did=did,
|
||||
scid=scid, tid=oid, only_sql=True)
|
||||
elif diff_schema:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
|
||||
diff_schema=diff_schema, json_resp=False)
|
||||
else:
|
||||
sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, tid=oid,
|
||||
json_resp=False)
|
||||
return sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, TypeView)
|
||||
TypeView.register_node_view(blueprint)
|
||||
+3
-1
@@ -26,12 +26,14 @@ FROM pg_enum
|
||||
{# The SQL given below will fetch range type#}
|
||||
{% if type == 'r' %}
|
||||
SELECT rngsubtype, st.typname,
|
||||
rngcollation, col.collname,
|
||||
rngcollation,
|
||||
CASE WHEN n.nspname IS NOT NULL THEN concat(quote_ident(n.nspname), '.', quote_ident(col.collname)) ELSE col.collname END AS collname,
|
||||
rngsubopc, opc.opcname,
|
||||
rngcanonical, rngsubdiff
|
||||
FROM pg_range
|
||||
LEFT JOIN pg_type st ON st.oid=rngsubtype
|
||||
LEFT JOIN pg_collation col ON col.oid=rngcollation
|
||||
LEFT JOIN pg_namespace n ON col.collnamespace=n.oid
|
||||
LEFT JOIN pg_opclass opc ON opc.oid=rngsubopc
|
||||
WHERE rngtypid={{tid}}::oid;
|
||||
{% endif %}
|
||||
Loaded 100 of 194 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user