Compare commits

..
40 Commits
Author SHA1 Message Date
Aditya Toshniwal 91ad54d17b Fixed an issue where query tool shortcut would trigger the callback twice. #9157 2025-10-14 14:33:17 +05:30
Akshay Joshi ea5ee74205 Update version for release v9.9 2025-10-13 20:51:55 +05:30
Anil Sahoo 5f22b4e2d2 Fixed following issues related to auto-update:
1. Fixed the issue where auto-update was not working for macOS x64 arch machines as pgadmin4 zip file name has x86_64 in it.
2. Improved error handling in the /upgrade_check API by replacing the static “Failed to check for update” message for Windows users with a dynamic error message.
3. Fixed the CSS issue affecting the close icon in the warning notifier.
4. Removed trailing periods from helper texts and notifier messages in the app’s auto-update workflow. #9133
2025-10-13 17:25:14 +05:30
Rohit Bhati 758bbc7272 Enable depends on extension option on for functions. 2025-10-13 11:39:37 +05:30
rlbxku1r 618e03b65f Update Japanese translation for v9.9 2025-10-13 11:38:35 +05:30
Akshay Joshi e9b97d61f8 1) Pin pywinpty due to https://github.com/andfoy/pywinpty/issues/545
2) Remove scram_client_key and scram_server_key from the connection string parameter
   as it is not meant to be specified directly by users or client applications.
2025-10-10 13:07:32 +05:30
Domenico Sgarbossa 83377d4a50 Italian translation updated for v9.9 2025-10-10 13:06:34 +05:30
Aditya Toshniwal c03d21899b Updated message catalogs for v9.9 2025-10-10 10:07:42 +05:30
Koren Peretz d03a0cdce6 Add support for initializing the pgAdmin4 Kubernetes Helm chart. #9225 2025-10-08 14:41:00 +05:30
Akshay Joshi f3567518d3 Added option to skip the password dialog when using an identity file. #6996
1. Don't ask for the SSH Tunnel or Database server password if it is already saved.
2. Modified the generic error message from the SSH Tunnel library.
2025-10-07 13:13:37 +05:30
Akshay Joshi b30520adc0 Updated Python and Javascript dependencies. 2025-10-06 17:33:12 +05:30
Yogesh Mahajan c6af61afd3 Implement pre and post scenario SQL execution in subscription ResQL tests to manage publication lifecycle. #8932 2025-10-03 12:12:15 +05:30
Akshay Joshi 04024c7f61 Updated Python and Javascript dependencies. 2025-10-01 15:27:23 +05:30
Rohit Bhati 9e6ab295df Add support of DEPENDS/NO DEPENDS ON EXTENSION for ALTER FUNCTION. #6385 2025-10-01 13:49:03 +05:30
Akshay Joshi 5c9acc1c3d 1) Added PG 18 in the github runner.
2) Added PG 18 in the docker container file.
2025-09-29 13:40:03 +05:30
Anil Sahoo c75bba03c2 1) Added 'failover' parameter support in CREATE and ALTER SUBSCRIPTION for PostgreSQL v17+. #8932
2) Added 'two_phase' parameter support for ALTER SUBSCRIPTION for PostgreSQL v18+.
3) Updated versioned_template_loader.py to prioritize v18+ templates.
4) Updated the default value of the streaming parameter in CREATE SUBSCRIPTION to 'parallel' in PG v18 (previously false).
2025-09-29 12:52:47 +05:30
Aditya Toshniwal 93bbadb994 Fixed an issue where the query tool displayed 'default' instead of 'null' for null text data in the data output. #9098 2025-09-29 12:37:25 +05:30
Akshay Joshi 42ff67c845 Updated Python and Javascript dependencies. 2025-09-25 15:50:14 +05:30
Yogesh Mahajan 5376d88444 Update the PATH variable with the newly installed EPAS directory to use the correct pg_config. 2025-09-24 15:55:10 +05:30
Yogesh Mahajan f733d124bd Update the PATH variable with the newly installed PostgreSQL directory to use the correct pg_config. 2025-09-24 14:55:56 +05:30
Aditya Toshniwal 7ff3c4bbeb Fixed an issue where shortcuts are not working as expected on multiple keyboard layouts. #9157 2025-09-17 11:34:15 +05:30
Aditya Toshniwal e5590797c0 Fixed an issue where saving the newly changed preferences was not reflecting on the preferences tab. #9158 2025-09-16 14:09:11 +05:30
Akshay Joshi 8576a5e7e6 Updated Javascript dependencies. 2025-09-15 09:45:05 +02:00
Akshay Joshi 3e66b6f7be 1) Added "MULTIRANGE_TYPE_NAME" option while creating a Range Type. #6394
2) Added "SUBSCRIPT" option while creating an External Type. #6395
2025-09-11 14:27:27 +05:30
Akshay Joshi 2fd2a144f1 Updated Python and Javascript dependecies. 2025-09-08 16:34:56 +05:30
Pravesh Sharma 500a5c7101 Fixed an issue where the pgAdmin configuration database wasn't being created on a fresh install when an external database was used for the configuration. #9125 2025-09-02 19:25:04 +05:30
Khushboo Vashi 5498682934 Update version for release v9.8 2025-09-01 16:39:08 +05:30
Khushboo Vashi cdeb18fcbb Fixed Cross-Origin Opener Policy (COOP) vulnerability in the OAuth 2.0 authentication flow (CVE-2025-9636). #9114 2025-09-01 16:34:18 +05:30
Aditya Toshniwal 0de635cc4c Fixed an issue where editor shortcuts fail when using Option key combinations on macOS, due to macOS treating Option+Key as a different key input. #9116 2025-09-01 16:21:03 +05:30
Akshay Joshi e09af0a0e9 Updated release note. 2025-08-28 16:18:38 +05:30
Akshay Joshi ade57d4ec4 Updated Python and JavaScript dependencies. 2025-08-28 12:56:20 +05:30
Rohit Bhati fc41c795f1 Add menu items for truncating foreign tables. #6396 2025-08-28 10:23:46 +05:30
Pravesh Sharma 7caaf2de82 Fixed an issue where pgAdmin config migration was failing while upgrading to v9.7 #9095 2025-08-28 10:15:35 +05:30
Akshay Joshi 09bc544e83 Pin Paramiko to version 3.5.1 to fix the DSSKey error introduced in the latest release. #9090 2025-08-25 18:09:45 +05:30
Domenico Sgarbossa 42a47126aa Italian translation update 2025-08-25 18:08:23 +05:30
Aditya Toshniwal db87df8f82 Remove usage of BrowserFS as it is deprecated. #7448 2025-08-25 14:34:33 +05:30
Aditya Toshniwal 15c212a2df Change the default pgAdmin theme to System. #9093 2025-08-25 12:33:27 +05:30
Yogesh Mahajan 68627ab44e Allow user to configure security related gunicorn parameters. #8891 2025-08-25 11:52:07 +05:30
Pravesh Sharma 800fdce316 Unpin Electron version 35.x as the GTK crash issue has been resolved upstream. 2025-08-22 11:32:58 +05:30
Akshay Joshi a5557b466c Updated Python and Javascript dependencies. 2025-08-21 13:54:07 +05:30
202 changed files with 21343 additions and 15652 deletions

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
pgver: [13, 14, 15, 16, 17]
pgver: [13, 14, 15, 16, 17, 18]
runs-on: ubuntu-22.04
@@ -73,6 +73,14 @@ jobs:
IF %ERRORLEVEL% EQU 3010 cmd /c "exit /b 0"
shell: cmd
- name: Add pg_config path to PATH
shell: pwsh
run: |
$pgPath = "C:\\EPAS\\${{ matrix.pgver }}\\bin"
Write-Output $pgPath
Add-Content -Path $env:GITHUB_PATH -Value $pgPath
pg_config --version
- name: Create the tablespace directory on Linux
if: ${{ matrix.os == 'ubuntu-22.04' }}
run: |
@@ -97,8 +105,13 @@ jobs:
run: |
# Note: we use a custom port for PostgreSQL as the runner may already have a version of PostgreSQL installed
sudo su -c "echo local all all trust > /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host all all 127.0.0.1/32 trust >> /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host all all ::1/128 trust >> /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host replication postgres 127.0.0.1/32 trust >> /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host replication postgres ::1/128 trust >> /etc/edb-as/${{ matrix.pgver }}/main/pg_hba.conf"
sudo sed -i "s/port = 544[0-9]/port = 58${{ matrix.pgver }}/g" /etc/edb-as/${{ matrix.pgver }}/main/postgresql.conf
sudo sed -i "s/shared_preload_libraries = '/shared_preload_libraries = '\$libdir\/plugin_debugger,/g" /etc/edb-as/${{ matrix.pgver }}/main/postgresql.conf
echo "wal_level = logical" | sudo tee -a /etc/edb-as/${{ matrix.pgver }}/main/postgresql.conf
sudo su - enterprisedb -c "mkdir -p /var/run/edb-as/${{ matrix.pgver }}-main.epas_stat_tmp"
sudo systemctl restart edb-as@${{ matrix.pgver }}-main
@@ -107,6 +120,16 @@ jobs:
sleep 2
done
- name: Start PostgreSQL on Windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
echo host replication postgres 127.0.0.1/32 trust >> "C:\EPAS\${{ matrix.pgver }}\data\pg_hba.conf"
echo host replication postgres ::1/128 trust >> "C:\EPAS\${{ matrix.pgver }}\data\pg_hba.conf"
echo wal_level = logical >> "C:\EPAS\${{ matrix.pgver }}\data\postgresql.conf"
net stop epas-${{ matrix.pgver }}
net start epas-${{ matrix.pgver }}
shell: cmd
- name: Create pgagent extension on Linux
if: ${{ matrix.os == 'ubuntu-22.04' && matrix.pgver <= 16 }}
run: psql -U enterprisedb -d postgres -p 58${{ matrix.pgver }} -c 'CREATE EXTENSION IF NOT EXISTS pgagent;'
+30 -1
View File
@@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-22.04, windows-latest]
pgver: [13, 14, 15, 16, 17]
pgver: [13, 14, 15, 16, 17, 18]
runs-on: ${{ matrix.os }}
@@ -64,6 +64,7 @@ jobs:
brew install postgresql@${{ matrix.pgver }}
echo "/opt/homebrew/opt/postgresql@${{ matrix.pgver }}/bin" >> $GITHUB_PATH
- name: Uninstall PostgreSQL if already present on windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
@@ -85,6 +86,14 @@ jobs:
IF %ERRORLEVEL% EQU 3010 cmd /c "exit /b 0"
shell: cmd
- name: Add pg_config path to PATH
shell: pwsh
run: |
$pgPath = "C:\\PostgreSQL\\${{ matrix.pgver }}\\bin"
Write-Output $pgPath
Add-Content -Path $env:GITHUB_PATH -Value $pgPath
pg_config --version
- name: Create the tablespace directory on Linux
if: ${{ matrix.os == 'ubuntu-22.04' }}
run: |
@@ -107,8 +116,13 @@ jobs:
if: ${{ matrix.os == 'ubuntu-22.04' }}
run: |
sudo su -c "echo local all all trust > /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host all all 127.0.0.1/32 trust >> /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host all all ::1/128 trust >> /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host replication postgres 127.0.0.1/32 trust >> /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
sudo su -c "echo host replication postgres ::1/128 trust >> /etc/postgresql/${{ matrix.pgver }}/main/pg_hba.conf"
sudo sed -i "s/port = 543[0-9]/port = 59${{ matrix.pgver }}/g" /etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf
sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = '\$libdir\/plugin_debugger'/g" /etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf
echo "wal_level = logical" | sudo tee -a /etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf
sudo su - postgres -c "/usr/lib/postgresql/${{ matrix.pgver }}/bin/postgres -D /var/lib/postgresql/${{ matrix.pgver }}/main -c config_file=/etc/postgresql/${{ matrix.pgver }}/main/postgresql.conf &"
until sudo runuser -l postgres -c "pg_isready -p 59${{ matrix.pgver }}" 2>/dev/null; do
@@ -124,7 +138,12 @@ jobs:
if: ${{ matrix.os == 'macos-latest' }}
run: |
echo local all all trust > /opt/homebrew/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
echo 'host all all 127.0.0.1/32 trust' >> /opt/homebrew/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
echo 'host all all ::1/128 trust' >> /opt/homebrew/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
echo 'host replication postgres 127.0.0.1/32 trust' >> /opt/homebrew/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
echo 'host replication postgres ::1/128 trust' >> /opt/homebrew/var/postgresql@${{ matrix.pgver }}/pg_hba.conf
sed -i '' "s/#port = 543[0-9]/port = 59${{ matrix.pgver }}/g" /opt/homebrew/var/postgresql@${{ matrix.pgver }}/postgresql.conf
echo "wal_level = logical" >> /opt/homebrew/var/postgresql@${{ matrix.pgver }}/postgresql.conf
brew services restart postgresql@${{ matrix.pgver }}
until /opt/homebrew/opt/postgresql@${{ matrix.pgver }}/bin/pg_isready -p 59${{ matrix.pgver }} 2>/dev/null; do
@@ -134,6 +153,16 @@ jobs:
psql postgres -p 59${{ matrix.pgver }} -c 'CREATE ROLE postgres SUPERUSER LOGIN;'
- name: Start PostgreSQL on Windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
echo host replication postgres 127.0.0.1/32 trust >> "C:\PostgreSQL\${{ matrix.pgver }}\data\pg_hba.conf"
echo host replication postgres ::1/128 trust >> "C:\PostgreSQL\${{ matrix.pgver }}\data\pg_hba.conf"
echo wal_level = logical >> "C:\PostgreSQL\${{ matrix.pgver }}\data\postgresql.conf"
net stop postgresql-x64-${{ matrix.pgver }}
net start postgresql-x64-${{ matrix.pgver }}
shell: cmd
- name: Install Python dependencies on Linux and macOS
if: ${{ matrix.os == 'macos-latest' || matrix.os == 'ubuntu-22.04' }}
run: make install-python-testing
+11 -11
View File
@@ -120,21 +120,16 @@ RUN rm -rf /pgadmin4/docs/en_US/_build/html/_static/*.png
# Create additional builders to get all of the PostgreSQL utilities
#########################################################################
FROM postgres:12-alpine AS pg12-builder
FROM postgres:13-alpine AS pg13-builder
FROM postgres:14-alpine AS pg14-builder
FROM postgres:15-alpine AS pg15-builder
FROM postgres:16-alpine AS pg16-builder
FROM postgres:17-alpine AS pg17-builder
FROM postgres:18-alpine AS pg18-builder
FROM alpine:latest AS tool-builder
# Copy the PG binaries
COPY --from=pg12-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-12/
COPY --from=pg12-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-12/
COPY --from=pg12-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-12/
COPY --from=pg12-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-12/
COPY --from=pg13-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-13/
COPY --from=pg13-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-13/
COPY --from=pg13-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-13/
@@ -160,6 +155,11 @@ COPY --from=pg17-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-17/
COPY --from=pg17-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-17/
COPY --from=pg17-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-17/
COPY --from=pg18-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-18/
COPY --from=pg18-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-18/
COPY --from=pg18-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-18/
COPY --from=pg18-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-18/
#########################################################################
# Assemble everything into the final container.
#########################################################################
@@ -171,12 +171,12 @@ COPY --from=env-builder /venv /venv
# Copy in the tools
COPY --from=tool-builder /usr/local/pgsql /usr/local/
COPY --from=pg17-builder /usr/local/lib/libpq.so.5.17 /usr/lib/
COPY --from=pg17-builder /usr/lib/libzstd.so.1.5.7 /usr/lib/
COPY --from=pg17-builder /usr/lib/liblz4.so.1.10.0 /usr/lib/
COPY --from=pg18-builder /usr/local/lib/libpq.so.5.18 /usr/lib/
COPY --from=pg18-builder /usr/lib/libzstd.so.1.5.7 /usr/lib/
COPY --from=pg18-builder /usr/lib/liblz4.so.1.10.0 /usr/lib/
RUN ln -s libpq.so.5.17 /usr/lib/libpq.so.5 && \
ln -s libpq.so.5.17 /usr/lib/libpq.so && \
RUN ln -s libpq.so.5.18 /usr/lib/libpq.so.5 && \
ln -s libpq.so.5.18 /usr/lib/libpq.so && \
ln -s libzstd.so.1.5.7 /usr/lib/libzstd.so.1 && \
ln -s liblz4.so.1.10.0 /usr/lib/liblz4.so.1
+1 -1
View File
@@ -282,7 +282,7 @@ REM Main build sequence Ends
REM WGET
FOR /f "tokens=*" %%i IN ('npm info electron version') DO SET "ELECTRON_VERSION=%%i"
SET ELECTRON_VERSION="35.4.0"
:GET_NW
wget https://github.com/electron/electron/releases/download/v%ELECTRON_VERSION%/electron-v%ELECTRON_VERSION%-win32-x64.zip -O "%TMPDIR%\electron-v%ELECTRON_VERSION%-win32-x64.zip"
IF %ERRORLEVEL% NEQ 0 GOTO GET_NW
+1
View File
@@ -53,6 +53,7 @@ The default binary paths set in the container are as follows:
.. code-block:: bash
DEFAULT_BINARY_PATHS = {
'pg-18': '/usr/local/pgsql-18',
'pg-17': '/usr/local/pgsql-17',
'pg-16': '/usr/local/pgsql-16',
'pg-15': '/usr/local/pgsql-15',
+3
View File
@@ -41,6 +41,9 @@ Use the fields in the *Definition* tab to define the function:
will change to an input text field.
* Use the drop-down listbox next to *Language* to select the implementation
language. The default is *sql*.
* Use the drop-down listbox next to *Depends on extensions* to select the extension that this function
depends on (for example, plpgsql). If set, dropping the extension will automatically drop the
function as well.
* Use the fields in the *Arguments* to define an argument. Click the *Add*
icon (+) to set parameters and values for the argument:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 72 KiB

+3 -3
View File
@@ -81,9 +81,9 @@ following options (in alphabetical order):
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
| *Trigger(s)* | Click to *Disable* or *Enable* trigger(s) for the currently selected table. Options are displayed on the flyout menu. |
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
| *Truncate* | Click to remove all rows from a table (*Truncate*), to remove all rows from a table and its child tables |
| | (*Truncate Cascade*) or to remove all rows from a table and automatically restart sequences owned by columns |
| | (*Truncate Restart Identity*). Options are displayed on the flyout menu. |
| *Truncate* | Click to remove all rows from a table/foreign tables (*Truncate*), to remove all rows from a table/foreign tables and |
| | its child tables (*Truncate Cascade*) or to remove all rows from a table/foreign tables and automatically restart |
| | sequences owned by columns (*Truncate Restart Identity*). Options are displayed on the flyout menu. |
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
| *View Data* | Click to access a context menu that provides several options for viewing data (see below). |
+-----------------------------+--------------------------------------------------------------------------------------------------------------------------+
+2
View File
@@ -12,6 +12,8 @@ notes for it.
:maxdepth: 1
release_notes_9_9
release_notes_9_8
release_notes_9_7
release_notes_9_6
release_notes_9_5
+39
View File
@@ -0,0 +1,39 @@
***********
Version 9.8
***********
Release date: 2025-09-04
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v9.7.
Supported Database Servers
**************************
**PostgreSQL**: 13, 14, 15, 16 and 17
**EDB Advanced Server**: 13, 14, 15, 16 and 17
Bundled PostgreSQL Utilities
****************************
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 17.5
New features
************
| `Issue #6396 <https://github.com/pgadmin-org/pgadmin4/issues/6396>`_ - Add menu items for truncating foreign tables.
| `Issue #7928 <https://github.com/pgadmin-org/pgadmin4/issues/7928>`_ - Added Debian Trixie as a supported platform for pgAdmin.
| `Issue #8891 <https://github.com/pgadmin-org/pgadmin4/issues/8891>`_ - Allow user to configure security related gunicorn parameters.
| `Issue #9093 <https://github.com/pgadmin-org/pgadmin4/issues/9093>`_ - Change the default pgAdmin theme to System.
Housekeeping
************
| `Issue #7448 <https://github.com/pgadmin-org/pgadmin4/issues/7448>`_ - Remove usage of BrowserFS as it is deprecated.
Bug fixes
*********
| `Issue #9090 <https://github.com/pgadmin-org/pgadmin4/issues/9090>`_ - Pin Paramiko to version 3.5.1 to fix the DSSKey error introduced in the latest release.
| `Issue #9095 <https://github.com/pgadmin-org/pgadmin4/issues/9095>`_ - Fixed an issue where pgAdmin config migration was failing while upgrading to v9.7.
| `Issue #9114 <https://github.com/pgadmin-org/pgadmin4/issues/9114>`_ - Fixed Cross-Origin Opener Policy (COOP) vulnerability in the OAuth 2.0 authentication flow (CVE-2025-9636).
| `Issue #9116 <https://github.com/pgadmin-org/pgadmin4/issues/9116>`_ - Fixed an issue where editor shortcuts fail when using Option key combinations on macOS, due to macOS treating Option+Key as a different key input.
+40
View File
@@ -0,0 +1,40 @@
***********
Version 9.9
***********
Release date: 2025-10-16
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v9.8.
Supported Database Servers
**************************
**PostgreSQL**: 13, 14, 15, 16, 17 and 18
**EDB Advanced Server**: 13, 14, 15, 16 and 17
Bundled PostgreSQL Utilities
****************************
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 17.5
New features
************
| `Issue #6385 <https://github.com/pgadmin-org/pgadmin4/issues/6385>`_ - Add support of DEPENDS/NO DEPENDS ON EXTENSION for ALTER FUNCTION.
| `Issue #6394 <https://github.com/pgadmin-org/pgadmin4/issues/6394>`_ - Added "MULTIRANGE_TYPE_NAME" option while creating a Range Type.
| `Issue #6395 <https://github.com/pgadmin-org/pgadmin4/issues/6395>`_ - Added "SUBSCRIPT" option while creating a External Type.
| `Issue #6996 <https://github.com/pgadmin-org/pgadmin4/issues/6996>`_ - Added option to skip the password dialog when using an identity file.
| `Issue #8932 <https://github.com/pgadmin-org/pgadmin4/issues/8932>`_ - Added 'failover' and 'two_phase' parameter support in CREATE/ALTER SUBSCRIPTION for PostgreSQL v17+.
| `Issue #9225 <https://github.com/pgadmin-org/pgadmin4/issues/9225>`_ - Add support for initializing the pgAdmin4 Kubernetes Helm chart.
Housekeeping
************
Bug fixes
*********
| `Issue #9098 <https://github.com/pgadmin-org/pgadmin4/issues/9098>`_ - Fixed an issue where the query tool displayed 'default' instead of 'null' for null text data in the data output.
| `Issue #9125 <https://github.com/pgadmin-org/pgadmin4/issues/9125>`_ - Fixed an issue where the pgAdmin configuration database wasn't being created on a fresh install when an external database was used for the configuration.
| `Issue #9157 <https://github.com/pgadmin-org/pgadmin4/issues/9157>`_ - Fixed an issue where shortcuts are not working as expected on multiple keyboard layouts.
| `Issue #9158 <https://github.com/pgadmin-org/pgadmin4/issues/9158>`_ - Fixed an issue where saving the newly changed preferences was not reflecting on the preferences tab.
+3
View File
@@ -177,6 +177,9 @@ not be able to connect directly.
*Identity file* field to specify the location of the key file.
* If the SSH host is expecting a password of the user name or an identity file
if being used, use the *Password* field to specify the password.
* Check the box next to *Prompt for password?* to to have pgAdmin prompt for
a password if the identity file includes one. This setting applies only when
using an identity file, which may or may not require a password.
* Check the box next to *Save password?* to instruct pgAdmin to save the
password for future use. Use
:ref:`Clear SSH Tunnel Password <clear_saved_passwords>` to remove the saved
+1
View File
@@ -106,6 +106,7 @@ Use the *With* tab to define some parameters for a subscription:
* Move the *Run as owner?* switch to *true* position to specify all replication actions are performed as the subscription owner. If *false*, replication workers will perform actions on each table as the owner of that table. The default is *false*. This option is available only on PostgreSQL 16 and above.
* Use the *Password required?* to specify whether connections to the publisher made as a result of this subscription must use password authentication. This setting is ignored when the subscription is owned by a superuser. The default is true. Only superusers can set this value to *false*. This option is available only on PostgreSQL 16 and above.
* Use the *Origin* to specify whether the subscription will request the publisher to only send changes that don't have an origin or send changes regardless of origin. The default is *any*. This option is available only on PostgreSQL 16 and above.
* Use the *Failover* to specify whether the replication slots associated with the subscription are enabled to be synced to the standbys so that logical replication can be resumed from the new primary after failover. The default is false. This option is available only on PostgreSQL 17 and above.
Click the *SQL* tab to continue.
+8 -5
View File
@@ -109,17 +109,17 @@ On the *Optional-1* tab:
to select a type_modifier_output_function. It is allowed to omit the
type_modifier_output_function, in which case the default display format is the
stored typmod integer value enclosed in parentheses.
* Use the drop-down listbox next to the optional *Analyze function* field to
select a function for performing type-specific statistics collection for
columns of the data type.
* Use the drop-down listbox next to the optional *Subscript function* field to
select a function for allows the data type to be subscripted in SQL commands.
* Use the optional *Internal length* to specify a value for internal
representation.
* Move the *Variable?* switch to specify the internal representation is of
variable length (VARIABLE). The default is a fixed length positive integer.
* Specify a default value in the optional *Default* field in cases where a
column of the data type defaults to something other than the null value.
Specify the default with the DEFAULT key word. (A default can be overridden
by an explicit DEFAULT clause attached to a particular column.)
* Use the drop-down listbox next to the optional *Analyze function* field to
select a function for performing type-specific statistics collection for
columns of the data type.
* Use the drop-down listbox next to the optional *Category type* field to help
control which implicit cast will be applied in ambiguous situations.
* Move the *Preferred?* switch to *Yes* to specify the selected category type is
@@ -162,6 +162,9 @@ disabled.
values to a canonical form.
* Use the drop-down listbox next to *Sub-type diff function* to select a
user-defined subtype_diff function.
* Specify the optional *Multirange type name* parameter to specifies the
name of the corresponding multirange type. If not specified, this name is
chosen automatically.
If you select *Shell* in the *Type* field, the *Definition* tab displays the
*Shell* panel:
+2 -2
View File
@@ -5,8 +5,8 @@ Debian and Ubuntu.
## Supported platforms
* Debian 11 & 12
* Ubuntu 22.04, 24.04 & 24.10
* Debian 11, 12 & 13
* Ubuntu 22.04, 24.04 & 25.04
## Build configuration
+3 -2
View File
@@ -48,7 +48,8 @@ CA_FILE = '/etc/ssl/certs/ca-certificates.crt'
LOG_FILE = '/dev/null'
HELP_PATH = '../../docs'
DEFAULT_BINARY_PATHS = {
'pg': '/usr/local/pgsql-17',
'pg': '/usr/local/pgsql-18',
'pg-18': '/usr/local/pgsql-18',
'pg-17': '/usr/local/pgsql-17',
'pg-16': '/usr/local/pgsql-16',
'pg-15': '/usr/local/pgsql-15',
@@ -188,5 +189,5 @@ fi
if [ -n "${PGADMIN_ENABLE_TLS}" ]; then
exec /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" --keyfile /certs/server.key --certfile /certs/server.cert -c gunicorn_config.py run_pgadmin:app
else
exec /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" -c gunicorn_config.py run_pgadmin:app
exec /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --limit-request-fields "${GUNICORN_LIMIT_REQUEST_FIELDS:-100}" --limit-request-field_size "${GUNICORN_LIMIT_REQUEST_FIELD_SIZE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" -c gunicorn_config.py run_pgadmin:app
fi
+11
View File
@@ -0,0 +1,11 @@
apiVersion: v2
name: pgadmin4-helm
version: 9.9.0
description: 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.
home: https://pgadmin.org
sources: ["https://github.com/pgadmin-org/pgadmin4/tree/master/helm"]
maintainers:
- name: Koren Peretz
url: https://github.com/KorenP1
icon: data:image/png;base64,AAABAAEAiooAAAEAIACANAEAFgAAACgAAACKAAAAFAEAAAEAIAAAAAAAkCkBACMuAAAjLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAABk2cxNJRpMXeTaTKtk2gy05NoMu6TaDL7k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv2TaDLulGgy2JNoMrGTaDJ/lWYzPKpVVQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjmM5EpJpMXyTaDLdk2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMuWTaDKJk2wxGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJJtJAeSaTF8lGgy8pNoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy+JRoMYyJYjsNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkmg0MZRoMtiTaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDLkk2g0QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACSaDJbk2gy95NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/JRnMXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJRpMmuTaDL+k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDGHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk2kzWpNoMv2TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gy/5NoMv+TaDL/k2gLine truncated
appVersion: 9.9.0
+41
View File
@@ -0,0 +1,41 @@
# PgAdmin4 K8S Helm Chart
Its been a struggle to deploy pgadmin4 container on different restricted k8s distributions for example openshift, gke or vanilla k8s pod security standards.
This helm chart follows best security measures and practices and compatible with all different security contexts and restrictions.
Further explanation about the security implementation can be read here: https://korenp1.github.io
The helm chart also implements most pgadmin4 features, for instance, config_local.py, predefined server definitions or preferences.
The majority of features and values are covered in the helm chart but always can be more customable or tpl'able, open for contributions.
### Package && Push
The chart should dump its version and appVersion in the Chart.yaml file every release and pushed to docker.io/dpage repository.
`helm package . && helm push pgadmin4-helm-<VERSION>.tgz oci://docker.io/dpage`
### Installation Example:
`helm install mypgadmin4 oci://docker.io/dpage/pgadmin4-helm --set ingress.enabled=true`
### Important Values
| Value | Description | Default |
| --------- | ----------- | ------- |
| `containerPort` | Internal PgAdmin4 Port | `5050` |
| `image.registry` | Image registry | `"docker.io"` |
| `image.repository` | Image Repository | `"dpage/pgadmin4"` |
| `image.tag` | Image tag (If empty, will use .Chart.AppVersion) | `""` |
| `auth.email` | Admin Email | `"admin@pgadmin.org"` |
| `auth.password` | Admin password (If both auth.password and auth.existingSecret are empty, the password will be randomly generated) | `""` |
| `auth.existingSecret` | Existing secret name for admin password (If both auth.password and auth.existingSecret are empty, the password will be randomly generated) | `""` |
| `extraEnvVars` | Extra environment variables | `[]` |
| `config_local.enabled` | Whether to mount config_local.py file | `false` |
| `config_local.data` | config_local.py configuration content | `""` |
| `config_local.existingSecret` | Existing secret name containing config_local.py file | `""` |
| `serverDefinitions.enabled` | Whether to mount servers.json | `false` |
| `serverDefinitions.data` | Server definitions to import | `{}` |
| `preferences.enabled` | Whether to mount preferences.json | `false` |
| `preferences.data` | Preferences to load | `{}` |
| `resources.*` | Allocated requests and limits resources | `{"requests": {...}, "limits": {...}}` |
| `persistence.enabled` | PVC resource creation | `false` |
| `service.type` | Service type | `"ClusterIP"` |
| `service.loadBalancerIP` | Load balancer IP (Only if service.type is LoadBalancer) | `""` |
| `ingress.enabled` | Ingress resource creation | `false` |
| `ingress.hostname` | Ingress resource hostname | `"pgadmin4.local"` |
+11
View File
@@ -0,0 +1,11 @@
Thanks for using PgAdmin4 Helm Chart :)
Image: {{ template "pgadmin4.image" . }}
Credentials:
Email: {{ .Values.auth.email }}
Password: {{ printf "kubectl get secret %s -n %s -o jsonpath='{.data.%s}' | base64 -d" (include "pgadmin4.fullname" .) .Release.Namespace .Values.auth.passwordKey }}
Ingress: {{ ternary (tpl .Values.ingress.hostname .) "DISABLED" .Values.ingress.enabled }}
GOOD LUCK!
+28
View File
@@ -0,0 +1,28 @@
{{- define "pgadmin4.fullname" -}}
{{- tpl .Values.fullname . -}}
{{- end -}}
{{- define "pgadmin4.image" -}}
{{- printf "%s/%s:%s" (default .Values.image.registry .Values.global.imageRegistry) .Values.image.repository (default .Chart.AppVersion .Values.image.tag | toString) -}}
{{- end -}}
{{- define "pgadmin4.serviceAccountName" -}}
{{- default (ternary (include "pgadmin4.fullname" .) "default" .Values.serviceAccount.create) .Values.serviceAccount.name -}}
{{- end -}}
{{- define "renderSecurityContext" -}}
{{- $securityContext := omit .securityContext "enabled" -}}
{{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (ternary "true" "" (.context.Capabilities.APIVersions.Has "security.openshift.io/v1"))) -}}
{{- $securityContext = omit $securityContext "fsGroup" "runAsUser" "runAsGroup" -}}
{{- if not $securityContext.seLinuxOptions }}
{{- $securityContext = omit $securityContext "seLinuxOptions" -}}
{{- end -}}
{{- end -}}
{{- if $securityContext.privileged }}
{{- $securityContext = omit $securityContext "capabilities" -}}
{{- end -}}
{{- if not .context.Values.global.compatibility.appArmor.enabled }}
{{- $securityContext = omit $securityContext "appArmorProfile" -}}
{{- end -}}
{{- $securityContext | toYaml -}}
{{- end -}}
@@ -0,0 +1,14 @@
{{- if .Values.preferences.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "pgadmin4.fullname" . }}-preferences
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
data:
preferences.json: | {{ dict "preferences" .Values.preferences.data | toPrettyJson | nindent 4 }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if .Values.serverDefinitions.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "pgadmin4.fullname" . }}-server-definitions
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
data:
servers.json: | {{ tpl (dict "Servers" .Values.serverDefinitions.data | toYaml) . | fromYaml | toPrettyJson | nindent 4 }}
{{- end }}
+237
View File
@@ -0,0 +1,237 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ default "pgadmin4" .Values.commonLabels.app }}
{{- with omit .Values.commonLabels "app" }}
{{- . | toYaml | nindent 6 }}
{{- end }}
template:
metadata:
labels:
app: {{ default "pgadmin4" .Values.commonLabels.app }}
{{- with omit .Values.commonLabels "app" }}
{{- . | toYaml | nindent 8 }}
{{- end }}
{{- if or (not (empty .Values.commonAnnotations)) (not .Values.existingSecret) .Values.preferences.enabled .Values.serverDefinitions.enabled }}
annotations:
{{- with .Values.commonAnnotations }}
{{- . | toYaml | nindent 8 }}
{{- end }}
{{- if not .Values.existingSecret }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
{{- end }}
{{- if and .Values.config_local.enabled (empty .Values.config_local.existingSecret) }}
checksum/secret-config: {{ include (print $.Template.BasePath "/secret-config.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
checksum/configmap-server-definitions: {{ include (print $.Template.BasePath "/configmap-serverDefinitions.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.preferences.enabled }}
checksum/configmap-preferences: {{ include (print $.Template.BasePath "/configmap-preferences.yaml") . | sha256sum }}
{{- end }}
{{- end }}
spec:
{{- if or .Values.global.imagePullSecrets .Values.image.pullSecrets }}
imagePullSecrets: {{- concat .Values.global.imagePullSecrets .Values.image.pullSecrets | toYaml | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "pgadmin4.serviceAccountName" . }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- if .Values.podSecurityContext.enabled }}
securityContext: {{- include "renderSecurityContext" (dict "securityContext" .Values.podSecurityContext "context" .) | nindent 8 }}
enableServiceLinks: {{ .Values.enableServiceLinks }}
{{- end }}
volumes:
- name: empty-dir
emptyDir: {}
{{- if .Values.persistence.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ template "pgadmin4.fullname" . }}
{{- end }}
{{- if .Values.config_local.enabled }}
- name: config-local
secret:
secretName: {{ default (printf "%s-config" (include "pgadmin4.fullname" .)) .Values.config_local.existingSecret }}
items:
- key: {{ .Values.config_local.configKey }}
path: {{ .Values.config_local.configKey }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
- name: server-definitions
configMap:
name: {{ template "pgadmin4.fullname" . }}-server-definitions
items:
- key: servers.json
path: servers.json
{{- end }}
{{- if .Values.preferences.enabled }}
- name: preferences
configMap:
name: {{ template "pgadmin4.fullname" . }}-preferences
items:
- key: preferences.json
path: preferences.json
{{- end }}
{{- with .Values.extraVolumes }}
{{- . | toYaml | nindent 8 }}
{{- end }}
containers:
- name: pgadmin4
{{- if .Values.containerSecurityContext.enabled }}
securityContext: {{- include "renderSecurityContext" (dict "securityContext" .Values.containerSecurityContext "context" .) | nindent 12 }}
{{- end }}
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
protocol: TCP
containerPort: {{ .Values.containerPort }}
resources:
requests:
cpu: {{ .Values.resources.requests.cpu }}
memory: {{ .Values.resources.requests.memory }}
limits:
cpu: {{ .Values.resources.limits.cpu }}
memory: {{ .Values.resources.limits.memory }}
env:
- name: PGADMIN_DEFAULT_EMAIL
value: {{ .Values.auth.email }}
- name: PGADMIN_DEFAULT_PASSWORD
valueFrom:
secretKeyRef:
name: {{ default (include "pgadmin4.fullname" .) .Values.auth.existingSecret }}
key: {{ .Values.auth.passwordKey }}
- name: PGADMIN_LISTEN_PORT
value: {{ .Values.containerPort | quote }}
- name: PGADMIN_DISABLE_POSTFIX
value: {{ .Values.disablePostfix | quote }}
{{- with .Values.extraEnvVars }}
{{- tpl (. | toYaml) $ | nindent 14 }}
{{- end }}
volumeMounts:
- mountPath: /var/lib/pgadmin
{{- if .Values.persistence.enabled }}
name: data
{{- else }}
name: empty-dir
subPath: data
{{- end }}
- name: empty-dir
mountPath: /pgadmin4/config_distro.py
subPath: config_distro.py
- name: empty-dir
mountPath: /usr/bin/python3
subPath: python3
- name: empty-dir
mountPath: /tmp
subPath: tmp
- name: empty-dir
mountPath: /var/log/pgadmin
subPath: logs
{{- if .Values.config_local.enabled }}
- name: config-local
mountPath: /pgadmin4/config_local.py
subPath: {{ .Values.config_local.configKey }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
- name: server-definitions
mountPath: /pgadmin4/servers.json
subPath: servers.json
{{- end }}
{{- if .Values.preferences.enabled }}
- name: preferences
mountPath: /pgadmin4/preferences.json
subPath: preferences.json
{{- end }}
{{- with .Values.extraVolumes }}
{{- . | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.startupProbe.enabled }}
startupProbe: {{- omit .Values.startupProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe: {{- omit .Values.readinessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.livenessProbe.enabled }}
livenessProbe: {{- omit .Values.livenessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
initContainers:
- name: modify-config-distro-py-permissions
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["sh", "-x", "-c"]
args: ['cp /pgadmin4/config_distro.py . && chmod 777 config_distro.py']
workingDir: /emptyDir
volumeMounts:
- name: empty-dir
mountPath: /emptyDir
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 50m
memory: 64Mi
securityContext:
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- if .Values.global.compatibility.appArmor.enabled }}
appArmorProfile:
type: RuntimeDefault
{{- end }}
windowsOptions:
hostProcess: false
- name: unset-python3-cli-net-cap
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["sh", "-x", "-c"]
args: ['ls /usr/bin/python3.* | sort -V -r | head -n 1 | xargs -I {} cp {} python3']
workingDir: /emptyDir
volumeMounts:
- name: empty-dir
mountPath: /emptyDir
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 50m
memory: 64Mi
securityContext:
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- if .Values.global.compatibility.appArmor.enabled }}
appArmorProfile:
type: RuntimeDefault
{{- end }}
windowsOptions:
hostProcess: false
+4
View File
@@ -0,0 +1,4 @@
{{- range .Values.extraDeploy }}
---
{{ tpl (. | toYaml) $ }}
{{- end }}
+24
View File
@@ -0,0 +1,24 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- if or .Values.ingress.annotations .Values.commonAnnotations }}
annotations: {{ merge .Values.ingress.annotations .Values.commonAnnotations | toYaml | nindent 4 }}
{{- end }}
spec:
rules:
- host: {{ tpl .Values.ingress.hostname . }}
http:
paths:
- backend:
service:
name: {{ template "pgadmin4.fullname" . }}
port:
name: http
path: /
pathType: Prefix
{{- end }}
+20
View File
@@ -0,0 +1,20 @@
{{- if .Values.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
spec:
{{- if or .Values.global.defaultStorageClass .Values.persistence.storageClass }}
storageClassName: {{ default .Values.global.defaultStorageClass .Values.persistence.storageClass }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
accessModes: {{ .Values.persistence.accessModes }}
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
{{- if and .Values.config_local.enabled (empty .Values.config_local.existingSecret) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "pgadmin4.fullname" . }}-config
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
type: Opaque
stringData:
{{ .Values.config_local.configKey }}: | {{ tpl .Values.config_local.data . | nindent 4 }}
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
{{- if empty .Values.auth.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
type: Opaque
stringData:
{{ .Values.auth.passwordKey }}: {{ coalesce .Values.auth.password (dig "data" .Values.auth.passwordKey "" (lookup "v1" "Secret" .Release.Namespace (include "pgadmin4.fullname" .)) | b64dec) (randAlphaNum 12) | quote }}
{{- end }}
+25
View File
@@ -0,0 +1,25 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- if or .Values.service.annotations .Values.commonAnnotations }}
annotations: {{ merge .Values.service.annotations .Values.commonAnnotations | toYaml | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
{{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}
selector:
app: {{ default "pgadmin4" .Values.commonLabels.app }}
{{- with omit .Values.commonLabels "app" }}
{{- . | toYaml | nindent 4 }}
{{- end }}
ports:
- name: http
protocol: TCP
targetPort: http
port: {{ .Values.service.port }}
+13
View File
@@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "pgadmin4.serviceAccountName" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}
+155
View File
@@ -0,0 +1,155 @@
global:
imageRegistry: ""
defaultStorageClass: ""
imagePullSecrets: []
compatibility:
openshift:
adaptSecurityContext: auto
appArmor:
enabled: false
fullname: pgadmin4
image:
registry: docker.io
repository: dpage/pgadmin4
tag: ""
pullPolicy: IfNotPresent
pullSecrets: []
commonLabels:
app: pgadmin4
commonAnnotations: {}
extraDeploy: []
replicas: 1
containerPort: 5050
disablePostfix: true
enableServiceLinks: false
auth:
email: admin@pgadmin.org
password: ""
existingSecret: ""
passwordKey: password
extraEnvVars: []
# - name: PGADMIN_CONFIG_LOGIN_BANNER
# value: '"Welcome to pgAdmin4 :)"'
extraVolumes: []
extraVolumeMounts: []
config_local:
enabled: false
existingSecret: ""
configKey: config_local.py
data: ""
# data: |
# DEBUG = True
# JSON_LOGGER = True
# AUTHENTICATION_SOURCES = ['oauth2', 'internal']
serverDefinitions:
enabled: false
data: {}
# "1":
# Name: Minimally Defined Server
# Group: Servers
# Port: 5432
# Username: postgres
# Host: myHost
# MaintenanceDB: postgres
# ConnectionParameters:
# sslmode: prefer
# connect_timeout: 10
preferences:
enabled: false
data: {}
# misc:user_interface:theme: dark
# file_manager:options:file_upload_size: 500
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 250m
memory: 512Mi
persistence:
enabled: true
size: 1Gi
storageClass: ""
accessModes: ["ReadWriteOnce"]
service:
type: ClusterIP
port: 80
annotations: {}
loadBalancerIP: ""
serviceAccount:
create: true
name: ""
automountServiceAccountToken: false
ingress:
enabled: false
hostname: pgadmin4.local
annotations: {}
startupProbe:
enabled: false
httpGet:
path: /misc/ping
port: http
initialDelaySeconds: null
periodSeconds: null
timeoutSeconds: null
failureThreshold: null
readinessProbe:
enabled: true
httpGet:
path: /misc/ping
port: http
initialDelaySeconds: null
periodSeconds: null
timeoutSeconds: null
failureThreshold: null
livenessProbe:
enabled: false
httpGet:
path: /misc/ping
port: http
initialDelaySeconds: null
periodSeconds: null
timeoutSeconds: null
failureThreshold: null
podSecurityContext:
enabled: true
fsGroupChangePolicy: Always
sysctls: []
supplementalGroups: []
fsGroup: 1001
containerSecurityContext:
enabled: true
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
appArmorProfile:
type: RuntimeDefault
windowsOptions:
hostProcess: false
-2
View File
@@ -140,8 +140,6 @@ _build_runtime() {
fi
ELECTRON_VERSION="$(npm info electron version)"
# Can't use the latest as it is not compatible with few OS versions.
ELECTRON_VERSION="35.4.0"
pushd "${BUILDROOT}" > /dev/null || exit
while true;do
+10 -11
View File
@@ -1,5 +1,11 @@
# shellcheck shell=bash
# uname -m returns "x86_64" on Intel, but we need "x64"
ARCH="x64"
if [ "$(uname -m)" == "arm64" ]; then
ARCH="arm64"
fi
_setup_env() {
FUNCS_DIR=$(cd "$(dirname "$0")" && pwd)/../..
APP_RELEASE=$(grep "^APP_RELEASE" "${FUNCS_DIR}/web/version.py" | cut -d"=" -f2 | sed 's/ //g')
@@ -11,7 +17,7 @@ _setup_env() {
APP_LONG_VERSION=${APP_LONG_VERSION}-${APP_SUFFIX}
fi
BUNDLE_DIR="${BUILD_ROOT}/${APP_NAME}.app"
DMG_NAME="${DIST_ROOT}"/$(echo "${APP_NAME}" | sed 's/ //g' | awk '{print tolower($0)}')-"${APP_LONG_VERSION}-$(uname -m).dmg"
DMG_NAME="${DIST_ROOT}/$(echo "${APP_NAME}" | sed 's/ //g' | awk '{print tolower($0)}')-${APP_LONG_VERSION}-${ARCH}.dmg"
PYTHON_OS_VERSION="11"
}
@@ -27,21 +33,14 @@ _build_runtime() {
test -d "${BUILD_ROOT}" || mkdir "${BUILD_ROOT}"
# Get a fresh copy of electron
# uname -m returns "x86_64" on Intel, but we need "x64"
ELECTRON_ARCH="x64"
if [ "$(uname -m)" == "arm64" ]; then
ELECTRON_ARCH="arm64"
fi
ELECTRON_VERSION="$(npm info electron version)"
ELECTRON_VERSION="35.4.0"
pushd "${BUILD_ROOT}" > /dev/null || exit
while true;do
wget "https://github.com/electron/electron/releases/download/v${ELECTRON_VERSION}/electron-v${ELECTRON_VERSION}-darwin-${ELECTRON_ARCH}.zip" && break
rm "electron-v${ELECTRON_VERSION}-darwin-${ELECTRON_ARCH}.zip"
wget "https://github.com/electron/electron/releases/download/v${ELECTRON_VERSION}/electron-v${ELECTRON_VERSION}-darwin-${ARCH}.zip" && break
rm "electron-v${ELECTRON_VERSION}-darwin-${ARCH}.zip"
done
unzip "electron-v${ELECTRON_VERSION}-darwin-${ELECTRON_ARCH}.zip"
unzip "electron-v${ELECTRON_VERSION}-darwin-${ARCH}.zip"
popd > /dev/null || exit
# WGET END
+1
View File
@@ -38,6 +38,7 @@ WizardImageFile=sidebar.bmp
MinVersion={#MinimumWindowsVer}
SignTool=pgAdminSigntool
SignedUninstaller=yes
CloseApplications=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
+9 -7
View File
@@ -13,13 +13,13 @@
###############################################################################
Authlib==1.6.*
azure-identity==1.24.0
azure-identity==1.25.0
azure-mgmt-rdbms==10.1.0
azure-mgmt-resource==24.0.0
azure-mgmt-subscription==3.1.1
bcrypt==4.3.*
bcrypt==5.0.*
boto3==1.40.*
cryptography==45.0.*
cryptography==46.0.*
Flask-Babel==4.0.*
Flask-Compress==1.*
Flask-Login==0.*
@@ -34,24 +34,26 @@ Flask-WTF==1.2.*
Flask==3.1.*
google-api-python-client==2.*
google-auth-oauthlib==1.2.2
gssapi==1.9.*
gssapi==1.10.*
jsonformatter~=0.3.4
keyring==25.*
ldap3==2.*
libgravatar==1.0.*
paramiko==3.5.1
passlib==1.*
psutil==7.0.*
psycopg[c]==3.2.9
psutil==7.1.*
psycopg[c]==3.2.10
pyotp==2.*
python-dateutil==2.*
pytz==2025.*
# pinned for https://github.com/andfoy/pywinpty/issues/545
pywinpty==2.0.*; sys_platform=="win32"
qrcode[pil]==8.*; python_version >= '3.9'
setuptools==80.*
SQLAlchemy==2.*
sqlparse==0.*
sshtunnel==0.*
typer[all]==0.16.*
typer[all]==0.19.*
urllib3==1.26.*; python_version <= '3.9'
urllib3==2.5.*; python_version > '3.9'
user-agents==2.2.0
+5 -5
View File
@@ -12,13 +12,13 @@
},
"packageManager": "yarn@4.9.2",
"devDependencies": {
"electron": "37.2.6",
"eslint": "^9.33.0",
"eslint-plugin-unused-imports": "^4.1.4"
"electron": "38.2.1",
"eslint": "^9.37.0",
"eslint-plugin-unused-imports": "^4.2.0"
},
"dependencies": {
"axios": "^1.11.0",
"axios": "^1.12.0",
"electron-context-menu": "^4.1.0",
"electron-store": "^10.1.0"
"electron-store": "^11.0.2"
}
}
+5 -5
View File
@@ -21,24 +21,24 @@ export function updateConfigAndMenus(event, configStore, pgAdminMainScreen, menu
// This function registers autoUpdater event listeners ONCE
function registerAutoUpdaterEvents({ pgAdminMainScreen, configStore, menuCallbacks }) {
autoUpdater.on('checking-for-update', () => {
misc.writeServerLog('[Auto-Updater]: Checking for update...');
misc.writeServerLog('[Auto-Updater]: Checking for update.');
});
autoUpdater.on('update-available', () => {
updateConfigAndMenus('update-available', configStore, pgAdminMainScreen, menuCallbacks);
misc.writeServerLog('[Auto-Updater]: Update downloading...');
misc.writeServerLog('[Auto-Updater]: Update downloading.');
pgAdminMainScreen.webContents.send('notifyAppAutoUpdate', { update_downloading: true });
});
autoUpdater.on('update-not-available', () => {
updateConfigAndMenus('update-not-available', configStore, pgAdminMainScreen, menuCallbacks);
misc.writeServerLog('[Auto-Updater]: No update available...');
misc.writeServerLog('[Auto-Updater]: No update available.');
pgAdminMainScreen.webContents.send('notifyAppAutoUpdate', { no_update_available: true });
});
autoUpdater.on('update-downloaded', () => {
updateConfigAndMenus('update-downloaded', configStore, pgAdminMainScreen, menuCallbacks);
misc.writeServerLog('[Auto-Updater]: Update downloaded...');
misc.writeServerLog('[Auto-Updater]: Update downloaded.');
pgAdminMainScreen.webContents.send('notifyAppAutoUpdate', { update_downloaded: true });
});
@@ -82,7 +82,7 @@ function handleSendDataForAppUpdate({
try {
autoUpdater.setFeedURL({ url: serverUrl });
misc.writeServerLog('[Auto-Updater]: Initiating update check...');
misc.writeServerLog('[Auto-Updater]: Initiating update check.');
autoUpdater.checkForUpdates();
} catch (err) {
misc.writeServerLog('[Auto-Updater]: Error setting autoUpdater feed URL: ' + err.message);
+1 -1
View File
@@ -75,7 +75,7 @@ function handleAutoUpdateMenu(menuFile, configStore, callbacks) {
menuFile.submenu.unshift({
name: 'mnu_restart_to_update',
id: 'mnu_restart_to_update',
label: 'Restart to Update...',
label: 'Restart to Update',
enabled: true,
priority: 998,
click: callbacks['restart_to_update'],
+2 -2
View File
@@ -443,14 +443,14 @@ function notifyUpdateInstalled() {
try {
// Notify renderer
if (pgAdminMainScreen) {
misc.writeServerLog('[Auto-Updater]: Update installed successfully...');
misc.writeServerLog('[Auto-Updater]: Update installed successfully.');
setTimeout(() => {
pgAdminMainScreen.webContents.send('notifyAppAutoUpdate', {update_installed: true});
}, 10000);
} else {
// If main screen not ready, wait and send after it's created
app.once('browser-window-created', (event, window) => {
misc.writeServerLog('[Auto-Updater]: Update installed successfully...');
misc.writeServerLog('[Auto-Updater]: Update installed successfully.');
setTimeout(() => {
pgAdminMainScreen.webContents.send('notifyAppAutoUpdate', {update_installed: true});
}, 10000);
+153 -125
View File
@@ -24,14 +24,14 @@ __metadata:
languageName: node
linkType: hard
"@eslint-community/eslint-utils@npm:^4.2.0":
version: 4.7.0
resolution: "@eslint-community/eslint-utils@npm:4.7.0"
"@eslint-community/eslint-utils@npm:^4.8.0":
version: 4.9.0
resolution: "@eslint-community/eslint-utils@npm:4.9.0"
dependencies:
eslint-visitor-keys: "npm:^3.4.3"
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
checksum: 10c0/c0f4f2bd73b7b7a9de74b716a664873d08ab71ab439e51befe77d61915af41a81ecec93b408778b3a7856185244c34c2c8ee28912072ec14def84ba2dec70adf
checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817
languageName: node
linkType: hard
@@ -53,19 +53,21 @@ __metadata:
languageName: node
linkType: hard
"@eslint/config-helpers@npm:^0.3.1":
version: 0.3.1
resolution: "@eslint/config-helpers@npm:0.3.1"
checksum: 10c0/f6c5b3a0b76a0d7d84cc93e310c259e6c3e0792ddd0a62c5fc0027796ffae44183432cb74b2c2b1162801ee1b1b34a6beb5d90a151632b4df7349f994146a856
"@eslint/config-helpers@npm:^0.4.0":
version: 0.4.0
resolution: "@eslint/config-helpers@npm:0.4.0"
dependencies:
"@eslint/core": "npm:^0.16.0"
checksum: 10c0/4e20c13aaeba1fa024983785df6625b36c8f4415b2433097982e1ccb08db9909e2f7bf60b793538d52ecfd572f2c4eec39a884c13c185cb6be35151f053beed5
languageName: node
linkType: hard
"@eslint/core@npm:^0.15.2":
version: 0.15.2
resolution: "@eslint/core@npm:0.15.2"
"@eslint/core@npm:^0.16.0":
version: 0.16.0
resolution: "@eslint/core@npm:0.16.0"
dependencies:
"@types/json-schema": "npm:^7.0.15"
checksum: 10c0/c17a6dc4f5a6006ecb60165cc38bcd21fefb4a10c7a2578a0cfe5813bbd442531a87ed741da5adab5eb678e8e693fda2e2b14555b035355537e32bcec367ea17
checksum: 10c0/f27496a244ccfdca3e0fbc3331f9da3f603bdf1aa431af0045a3205826789a54493bc619ad6311a9090eaf7bc25798ff4e265dea1eccd2df9ce3b454f7e7da27
languageName: node
linkType: hard
@@ -86,10 +88,10 @@ __metadata:
languageName: node
linkType: hard
"@eslint/js@npm:9.33.0":
version: 9.33.0
resolution: "@eslint/js@npm:9.33.0"
checksum: 10c0/4c42c9abde76a183b8e47205fd6c3116b058f82f07b6ad4de40de56cdb30a36e9ecd40efbea1b63a84d08c206aadbb0aa39a890197e1ad6455a8e542df98f186
"@eslint/js@npm:9.37.0":
version: 9.37.0
resolution: "@eslint/js@npm:9.37.0"
checksum: 10c0/84f98a6213522fc76ea104bd910f606136200bd918544e056a7a22442d3f9d5c3c5cd7f4cdf2499d49b1fa140155b87d597a1f16d01644920f05c228e9ca0378
languageName: node
linkType: hard
@@ -100,13 +102,13 @@ __metadata:
languageName: node
linkType: hard
"@eslint/plugin-kit@npm:^0.3.5":
version: 0.3.5
resolution: "@eslint/plugin-kit@npm:0.3.5"
"@eslint/plugin-kit@npm:^0.4.0":
version: 0.4.0
resolution: "@eslint/plugin-kit@npm:0.4.0"
dependencies:
"@eslint/core": "npm:^0.15.2"
"@eslint/core": "npm:^0.16.0"
levn: "npm:^0.4.1"
checksum: 10c0/c178c1b58c574200c0fd125af3e4bc775daba7ce434ba6d1eeaf9bcb64b2e9fea75efabffb3ed3ab28858e55a016a5efa95f509994ee4341b341199ca630b89e
checksum: 10c0/125614e902bb34c041da859794c47ac2ec4a814f5d9e7c4d37fcd34b38d8ee5cf1f97020d38d168885d9bf4046a9a7decb86b4cee8dac9eedcc6ad08ebafe204
languageName: node
linkType: hard
@@ -118,12 +120,12 @@ __metadata:
linkType: hard
"@humanfs/node@npm:^0.16.6":
version: 0.16.6
resolution: "@humanfs/node@npm:0.16.6"
version: 0.16.7
resolution: "@humanfs/node@npm:0.16.7"
dependencies:
"@humanfs/core": "npm:^0.19.1"
"@humanwhocodes/retry": "npm:^0.3.0"
checksum: 10c0/8356359c9f60108ec204cbd249ecd0356667359b2524886b357617c4a7c3b6aace0fd5a369f63747b926a762a88f8a25bc066fa1778508d110195ce7686243e1
"@humanwhocodes/retry": "npm:^0.4.0"
checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30
languageName: node
linkType: hard
@@ -134,14 +136,7 @@ __metadata:
languageName: node
linkType: hard
"@humanwhocodes/retry@npm:^0.3.0":
version: 0.3.1
resolution: "@humanwhocodes/retry@npm:0.3.1"
checksum: 10c0/f0da1282dfb45e8120480b9e2e275e2ac9bbe1cf016d046fdad8e27cc1285c45bb9e711681237944445157b430093412b4446c1ab3fc4bb037861b5904101d3b
languageName: node
linkType: hard
"@humanwhocodes/retry@npm:^0.4.2":
"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2":
version: 0.4.3
resolution: "@humanwhocodes/retry@npm:0.4.3"
checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42
@@ -207,20 +202,20 @@ __metadata:
linkType: hard
"@types/node@npm:*":
version: 24.2.1
resolution: "@types/node@npm:24.2.1"
version: 24.7.0
resolution: "@types/node@npm:24.7.0"
dependencies:
undici-types: "npm:~7.10.0"
checksum: 10c0/439a3c7edf88a298e0c92e46f670234070b892589c3b06e82cc86c47a7e1cf220f4a4b4736ec6ac7e4b9e1c40d7b6d443a1e22f99dd17f13f9dd15de3b32011b
undici-types: "npm:~7.14.0"
checksum: 10c0/f036c78062cb3a0d5c6586bf2dac347ed3f4af121cef4ab92c85c44e32be1c50aab5ba96955842b7f8165f0e0f1c8066d1813ae259372df6c0fa9fadb1116a3e
languageName: node
linkType: hard
"@types/node@npm:^22.7.7":
version: 22.17.1
resolution: "@types/node@npm:22.17.1"
version: 22.18.8
resolution: "@types/node@npm:22.18.8"
dependencies:
undici-types: "npm:~6.21.0"
checksum: 10c0/b04063bdabfc4146af05d14d4fd23ee68615194473d0ef971ddef549b80b791f52c8f93abdd8d1092ee0257f3dea862fa233519244fd051e79233cdce614de14
checksum: 10c0/54473730e7417b923fec427f62ed3204259acbd8e450a7593bad8ae02a75effcfcc864b34bf02c108eeb9c04a404791687f42b801bafa5264a8761f4df9122fd
languageName: node
linkType: hard
@@ -299,9 +294,9 @@ __metadata:
linkType: hard
"ansi-regex@npm:^6.0.1":
version: 6.1.0
resolution: "ansi-regex@npm:6.1.0"
checksum: 10c0/a91daeddd54746338478eef88af3439a7edf30f8e23196e2d6ed182da9add559c601266dbef01c2efa46a958ad6f1f8b176799657616c702b5b02e799e7fd8dc
version: 6.2.2
resolution: "ansi-regex@npm:6.2.2"
checksum: 10c0/05d4acb1d2f59ab2cf4b794339c7b168890d44dda4bf0ce01152a8da0213aca207802f930442ce8cd22d7a92f44907664aac6508904e75e038fa944d2601b30f
languageName: node
linkType: hard
@@ -315,9 +310,9 @@ __metadata:
linkType: hard
"ansi-styles@npm:^6.0.0":
version: 6.2.1
resolution: "ansi-styles@npm:6.2.1"
checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c
version: 6.2.3
resolution: "ansi-styles@npm:6.2.3"
checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868
languageName: node
linkType: hard
@@ -328,6 +323,20 @@ __metadata:
languageName: node
linkType: hard
"async-function@npm:^1.0.0":
version: 1.0.0
resolution: "async-function@npm:1.0.0"
checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73
languageName: node
linkType: hard
"async-generator-function@npm:^1.0.0":
version: 1.0.0
resolution: "async-generator-function@npm:1.0.0"
checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186
languageName: node
linkType: hard
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
@@ -345,14 +354,14 @@ __metadata:
languageName: node
linkType: hard
"axios@npm:^1.11.0":
version: 1.11.0
resolution: "axios@npm:1.11.0"
"axios@npm:^1.12.0":
version: 1.12.2
resolution: "axios@npm:1.12.2"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.4"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/5de273d33d43058610e4d252f0963cc4f10714da0bfe872e8ef2cbc23c2c999acc300fd357b6bce0fc84a2ca9bd45740fa6bb28199ce2c1266c8b1a393f2b36e
checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed
languageName: node
linkType: hard
@@ -487,20 +496,20 @@ __metadata:
languageName: node
linkType: hard
"conf@npm:^14.0.0":
version: 14.0.0
resolution: "conf@npm:14.0.0"
"conf@npm:^15.0.2":
version: 15.0.2
resolution: "conf@npm:15.0.2"
dependencies:
ajv: "npm:^8.17.1"
ajv-formats: "npm:^3.0.1"
atomically: "npm:^2.0.3"
debounce-fn: "npm:^6.0.0"
dot-prop: "npm:^9.0.0"
dot-prop: "npm:^10.0.0"
env-paths: "npm:^3.0.0"
json-schema-typed: "npm:^8.0.1"
semver: "npm:^7.7.2"
uint8array-extras: "npm:^1.4.0"
checksum: 10c0/d1472ea24dad78d0d33dee47a795dfefe92fcdf2633763a8b35563989f22b2658e768c9d338de8e8e5f9163525d22df9e5f8733094d822a8329f4571dedce208
uint8array-extras: "npm:^1.5.0"
checksum: 10c0/77713ffe61e1ec26713fba972b6a4f589a3c45872cf07f0e6499a3e54fe855d2c88bf80e148346b28abef0174e4bffcb98cc0a58dd42d451c936a045bd319113
languageName: node
linkType: hard
@@ -525,14 +534,14 @@ __metadata:
linkType: hard
"debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2":
version: 4.4.1
resolution: "debug@npm:4.4.1"
version: 4.4.3
resolution: "debug@npm:4.4.3"
dependencies:
ms: "npm:^2.1.3"
peerDependenciesMeta:
supports-color:
optional: true
checksum: 10c0/d2b44bc1afd912b49bb7ebb0d50a860dc93a4dd7d946e8de94abc957bb63726b7dd5aa48c18c2386c379ec024c46692e15ed3ed97d481729f929201e671fcd55
checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6
languageName: node
linkType: hard
@@ -595,12 +604,12 @@ __metadata:
languageName: node
linkType: hard
"dot-prop@npm:^9.0.0":
version: 9.0.0
resolution: "dot-prop@npm:9.0.0"
"dot-prop@npm:^10.0.0":
version: 10.1.0
resolution: "dot-prop@npm:10.1.0"
dependencies:
type-fest: "npm:^4.18.2"
checksum: 10c0/4bac49a2f559156811862ac92813906f70529c50da918eaab81b38dd869743c667d578e183607f5ae11e8ae2a02e43e98e32c8a37bc4cae76b04d5b576e3112f
type-fest: "npm:^5.0.0"
checksum: 10c0/b034a06f017909ed55c6c164ddea962ccdce3d88b9b092f7106a9b738116a4cd003db5d47a0c6e140e93adbf1922b5e3a147e3d4a124c8556862940446ba5f75
languageName: node
linkType: hard
@@ -616,13 +625,13 @@ __metadata:
linkType: hard
"electron-context-menu@npm:^4.1.0":
version: 4.1.0
resolution: "electron-context-menu@npm:4.1.0"
version: 4.1.1
resolution: "electron-context-menu@npm:4.1.1"
dependencies:
cli-truncate: "npm:^4.0.0"
electron-dl: "npm:^4.0.0"
electron-is-dev: "npm:^3.0.1"
checksum: 10c0/ec5b12107d8ddad419f41a486e325ff3dc7b17384c13f6d325611d12297064e6ca850e8f414a48df850b50c225f3ddd87af654bfbcbbcf6ac62619d46265ed60
checksum: 10c0/3e2eb5298a311f320734427fadb1cf22ef6685c8d86387d1a2d558b698b079de8eabb4d7a8790cab100cf5eba3607df887846067f5a805d1c011016b9eccdf70
languageName: node
linkType: hard
@@ -644,33 +653,33 @@ __metadata:
languageName: node
linkType: hard
"electron-store@npm:^10.1.0":
version: 10.1.0
resolution: "electron-store@npm:10.1.0"
"electron-store@npm:^11.0.2":
version: 11.0.2
resolution: "electron-store@npm:11.0.2"
dependencies:
conf: "npm:^14.0.0"
type-fest: "npm:^4.41.0"
checksum: 10c0/a527a1957b09decbbb36828e299bb06c239ed9a7d406ceda07abe84d2a9dfd1920120c63859e42c9c7a0922b95b840c4f4e5d8db90256814445f22a8a48de07e
conf: "npm:^15.0.2"
type-fest: "npm:^5.0.1"
checksum: 10c0/14a24b49f92b5fc818285a528a2032257dc3221fc3917ba94c0308f4c45bf468f92fb7ba401f1d7f0151bcf10487370448632e8a765dab47db20fc7b3f1925bb
languageName: node
linkType: hard
"electron@npm:37.2.6":
version: 37.2.6
resolution: "electron@npm:37.2.6"
"electron@npm:38.2.1":
version: 38.2.1
resolution: "electron@npm:38.2.1"
dependencies:
"@electron/get": "npm:^2.0.0"
"@types/node": "npm:^22.7.7"
extract-zip: "npm:^2.0.1"
bin:
electron: cli.js
checksum: 10c0/d0653bbaf6b449260d65d51aa12717ad8acaffce337d32e9892aea5cb70e1dc70f0da54393548595dd3a57cce1dbf699e3fa5d9155427f4151ada572f4430778
checksum: 10c0/f9be3bda71dfa4e04e28e4e23cb02a1103d822763d62d2b0bf9a553e8593a298fdfb47dbc0ed4a252a77ea05a890b4612370d8aa339a2b67dacbcd28c3713798
languageName: node
linkType: hard
"emoji-regex@npm:^10.3.0":
version: 10.4.0
resolution: "emoji-regex@npm:10.4.0"
checksum: 10c0/a3fcedfc58bfcce21a05a5f36a529d81e88d602100145fcca3dc6f795e3c8acc4fc18fe773fbf9b6d6e9371205edb3afa2668ec3473fa2aa7fd47d2a9d46482d
version: 10.5.0
resolution: "emoji-regex@npm:10.5.0"
checksum: 10c0/17cf84335a461fc23bf90575122ace2902630dc760e53299474cd3b0b5e4cfbc6c0223a389a766817538e5d20bf0f36c67b753f27c9e705056af510b8777e312
languageName: node
linkType: hard
@@ -760,16 +769,16 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-unused-imports@npm:^4.1.4":
version: 4.1.4
resolution: "eslint-plugin-unused-imports@npm:4.1.4"
"eslint-plugin-unused-imports@npm:^4.2.0":
version: 4.2.0
resolution: "eslint-plugin-unused-imports@npm:4.2.0"
peerDependencies:
"@typescript-eslint/eslint-plugin": ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
eslint: ^9.0.0 || ^8.0.0
peerDependenciesMeta:
"@typescript-eslint/eslint-plugin":
optional: true
checksum: 10c0/3899f64b0e8b23fa6b81e2754fc10f93d8741e051d70390a8100ca39af7878bde8625f234b76111af69562ef2512104b52c3703e986ccb3ac9adc07911896acf
checksum: 10c0/b6293323670dda64b0b5931ace1ab45f731e399e87da591c208da09c6bf89a84591b160b8e15e3b47f8f1f662dc80306368a60c09f833de0f6f1dbd97c247949
languageName: node
linkType: hard
@@ -797,18 +806,18 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:^9.33.0":
version: 9.33.0
resolution: "eslint@npm:9.33.0"
"eslint@npm:^9.37.0":
version: 9.37.0
resolution: "eslint@npm:9.37.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.2.0"
"@eslint-community/eslint-utils": "npm:^4.8.0"
"@eslint-community/regexpp": "npm:^4.12.1"
"@eslint/config-array": "npm:^0.21.0"
"@eslint/config-helpers": "npm:^0.3.1"
"@eslint/core": "npm:^0.15.2"
"@eslint/config-helpers": "npm:^0.4.0"
"@eslint/core": "npm:^0.16.0"
"@eslint/eslintrc": "npm:^3.3.1"
"@eslint/js": "npm:9.33.0"
"@eslint/plugin-kit": "npm:^0.3.5"
"@eslint/js": "npm:9.37.0"
"@eslint/plugin-kit": "npm:^0.4.0"
"@humanfs/node": "npm:^0.16.6"
"@humanwhocodes/module-importer": "npm:^1.0.1"
"@humanwhocodes/retry": "npm:^0.4.2"
@@ -843,7 +852,7 @@ __metadata:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10c0/1e1f60d2b62d9d65553e9af916a8dccf00eeedd982103f35bf58c205803907cb1fda73ef595178d47384ea80d8624a182b63682a6b15d8387e9a5d86904a2a2d
checksum: 10c0/30b71350b0e43542eeffa6f7380ed85c960055dde8003f17bf87d209a4a9afc6091bc0419aa32f86853e7ecef18790bdc4d678112b89dbebe61b69efcb1100e1
languageName: node
linkType: hard
@@ -948,9 +957,9 @@ __metadata:
linkType: hard
"fast-uri@npm:^3.0.1":
version: 3.0.6
resolution: "fast-uri@npm:3.0.6"
checksum: 10c0/74a513c2af0584448aee71ce56005185f81239eab7a2343110e5bad50c39ad4fb19c5a6f99783ead1cac7ccaf3461a6034fda89fffa2b30b6d99b9f21c2f9d29
version: 3.1.0
resolution: "fast-uri@npm:3.1.0"
checksum: 10c0/44364adca566f70f40d1e9b772c923138d47efeac2ae9732a872baafd77061f26b097ba2f68f0892885ad177becd065520412b8ffeec34b16c99433c5b9e2de7
languageName: node
linkType: hard
@@ -1040,28 +1049,38 @@ __metadata:
languageName: node
linkType: hard
"generator-function@npm:^2.0.0":
version: 2.0.1
resolution: "generator-function@npm:2.0.1"
checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8
languageName: node
linkType: hard
"get-east-asian-width@npm:^1.0.0":
version: 1.3.0
resolution: "get-east-asian-width@npm:1.3.0"
checksum: 10c0/1a049ba697e0f9a4d5514c4623781c5246982bdb61082da6b5ae6c33d838e52ce6726407df285cdbb27ec1908b333cf2820989bd3e986e37bb20979437fdf34b
version: 1.4.0
resolution: "get-east-asian-width@npm:1.4.0"
checksum: 10c0/4e481d418e5a32061c36fbb90d1b225a254cc5b2df5f0b25da215dcd335a3c111f0c2023ffda43140727a9cafb62dac41d022da82c08f31083ee89f714ee3b83
languageName: node
linkType: hard
"get-intrinsic@npm:^1.2.6":
version: 1.3.0
resolution: "get-intrinsic@npm:1.3.0"
version: 1.3.1
resolution: "get-intrinsic@npm:1.3.1"
dependencies:
async-function: "npm:^1.0.0"
async-generator-function: "npm:^1.0.0"
call-bind-apply-helpers: "npm:^1.0.2"
es-define-property: "npm:^1.0.1"
es-errors: "npm:^1.3.0"
es-object-atoms: "npm:^1.1.1"
function-bind: "npm:^1.1.2"
generator-function: "npm:^2.0.0"
get-proto: "npm:^1.0.1"
gopd: "npm:^1.2.0"
has-symbols: "npm:^1.1.0"
hasown: "npm:^2.0.2"
math-intrinsics: "npm:^1.1.0"
checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a
checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d
languageName: node
linkType: hard
@@ -1569,12 +1588,12 @@ __metadata:
version: 0.0.0-use.local
resolution: "pgadmin4@workspace:."
dependencies:
axios: "npm:^1.11.0"
electron: "npm:37.2.6"
axios: "npm:^1.12.0"
electron: "npm:38.2.1"
electron-context-menu: "npm:^4.1.0"
electron-store: "npm:^10.1.0"
eslint: "npm:^9.33.0"
eslint-plugin-unused-imports: "npm:^4.1.4"
electron-store: "npm:^11.0.2"
eslint: "npm:^9.37.0"
eslint-plugin-unused-imports: "npm:^4.2.0"
languageName: unknown
linkType: soft
@@ -1617,11 +1636,11 @@ __metadata:
linkType: hard
"pupa@npm:^3.1.0":
version: 3.1.0
resolution: "pupa@npm:3.1.0"
version: 3.3.0
resolution: "pupa@npm:3.3.0"
dependencies:
escape-goat: "npm:^4.0.0"
checksum: 10c0/02afa6e4547a733484206aaa8f8eb3fbfb12d3dd17d7ca4fa1ea390a7da2cb8f381e38868bbf68009c4d372f8f6059f553171b6a712d8f2802c7cd43d513f06c
checksum: 10c0/9707e0a7f00e5922d47527d1c8d88d4224b1e86502da2fca27943eb0e9bb218121c91fa0af6c30531a2ee5ade0c326b5d33c40fdf61bc593c4224027412fd9b7
languageName: node
linkType: hard
@@ -1773,11 +1792,11 @@ __metadata:
linkType: hard
"strip-ansi@npm:^7.1.0":
version: 7.1.0
resolution: "strip-ansi@npm:7.1.0"
version: 7.1.2
resolution: "strip-ansi@npm:7.1.2"
dependencies:
ansi-regex: "npm:^6.0.1"
checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4
checksum: 10c0/0d6d7a023de33368fd042aab0bf48f4f4077abdfd60e5393e73c7c411e85e1b3a83507c11af2e656188511475776215df9ca589b4da2295c9455cc399ce1858b
languageName: node
linkType: hard
@@ -1813,6 +1832,13 @@ __metadata:
languageName: node
linkType: hard
"tagged-tag@npm:^1.0.0":
version: 1.0.0
resolution: "tagged-tag@npm:1.0.0"
checksum: 10c0/91d25c9ffb86a91f20522cefb2cbec9b64caa1febe27ad0df52f08993ff60888022d771e868e6416cf2e72dab68449d2139e8709ba009b74c6c7ecd4000048d1
languageName: node
linkType: hard
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
version: 0.4.0
resolution: "type-check@npm:0.4.0"
@@ -1829,17 +1855,19 @@ __metadata:
languageName: node
linkType: hard
"type-fest@npm:^4.18.2, type-fest@npm:^4.41.0":
version: 4.41.0
resolution: "type-fest@npm:4.41.0"
checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4
"type-fest@npm:^5.0.0, type-fest@npm:^5.0.1":
version: 5.0.1
resolution: "type-fest@npm:5.0.1"
dependencies:
tagged-tag: "npm:^1.0.0"
checksum: 10c0/8d248edd9705e0da3cc14f4f4ca7fb40a6c5b2c822fe4ba8fc226743578bc229f66fa4ff66e7d4070806ab8312adc64199ce0f0836d20ede13922ced2ff36118
languageName: node
linkType: hard
"uint8array-extras@npm:^1.4.0":
version: 1.4.0
resolution: "uint8array-extras@npm:1.4.0"
checksum: 10c0/eaffd3388634b7e5e1496073b878dd19136043137d3e7e0d2a453e37f566a5a551e640819e1a6596c6df9b9d1f7b70884cc29db6a357bdd424811f3598d504dd
"uint8array-extras@npm:^1.5.0":
version: 1.5.0
resolution: "uint8array-extras@npm:1.5.0"
checksum: 10c0/0e74641ac7dadb02eadefc1ccdadba6010e007757bda824960de3c72bbe2b04e6d3af75648441f412148c4103261d54fcb60be45a2863beb76643a55fddba3bd
languageName: node
linkType: hard
@@ -1850,10 +1878,10 @@ __metadata:
languageName: node
linkType: hard
"undici-types@npm:~7.10.0":
version: 7.10.0
resolution: "undici-types@npm:7.10.0"
checksum: 10c0/8b00ce50e235fe3cc601307f148b5e8fb427092ee3b23e8118ec0a5d7f68eca8cee468c8fc9f15cbb2cf2a3797945ebceb1cbd9732306a1d00e0a9b6afa0f635
"undici-types@npm:~7.14.0":
version: 7.14.0
resolution: "undici-types@npm:7.14.0"
checksum: 10c0/e7f3214b45d788f03c51ceb33817be99c65dae203863aa9386b3ccc47201a245a7955fc721fb581da9c888b6ebad59fa3f53405214afec04c455a479908f0f14
languageName: node
linkType: hard
+11
View File
@@ -129,6 +129,17 @@ WEB_SERVER = 'Python'
# See https://tools.ietf.org/html/rfc7034 for more info.
X_FRAME_OPTIONS = "SAMEORIGIN"
# The Cross-Origin-Opener-Policy allows a website to control whether
# a new top-level document, opened using Window.open() or by navigating
# to a new page, is opened in the same browsing context group (BCG)
# or in a new browsing context group.
# Set to 'unsafe-none', 'same-origin-allow-popups', 'same-origin',
# or 'noopener-allow-popups'
CROSS_ORIGIN_OPENER_POLICY = "same-origin"
# The Content-Security-Policy header allows you to restrict how resources
# such as JavaScript, CSS, or pretty much anything that the browser loads.
# see https://content-security-policy.com/#source_list for more info
+76 -23
View File
@@ -15,11 +15,10 @@ Revises: e24b1c4def17
Create Date: 2025-07-15 12:27:48.780562
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.orm.session import Session
from pgadmin.model import Preferences, ModulePreference, PreferenceCategory,\
UserPreference
from pgadmin.browser import register_editor_preferences
from pgadmin.model import Preferences, ModulePreference, PreferenceCategory
# revision identifiers, used by Alembic.
@@ -29,21 +28,11 @@ branch_labels = None
depends_on = None
class Migration:
"""
This is a placeholder class for registering editor preferences
"""
def __init__(self, value=None):
self.editor_preference = value
def upgrade():
migration_obj = Migration()
register_editor_preferences(migration_obj, migration_gettext=lambda x: x)
session = Session(bind=op.get_bind())
pref_categories = ['keyboard_shortcuts', 'editor', 'Editor']
new_categories = ['keyboard_shortcuts', 'sql_formatting', 'options']
old_pref_categories = ['keyboard_shortcuts', 'editor', 'Editor']
new_pref_categories = ['keyboard_shortcuts', 'sql_formatting', 'options']
prefs = ['find', 'replace', 'goto_line_col',
'comment', 'format_sql', 'plain_editor_mode',
'code_folding', 'wrap_code', 'insert_pair_brackets',
@@ -53,14 +42,76 @@ def upgrade():
'data_type_case', 'spaces_around_operators', 'tab_size',
'use_spaces', 'expression_width', 'logical_operator_new_line',
'lines_between_queries', 'new_line_before_semicolon']
preference_map = {
'keyboard_shortcuts': [
'find', 'replace', 'goto_line_col', 'comment', 'format_sql'
],
'options': [
'plain_editor_mode', 'code_folding', 'cursor_blink_rate',
'wrap_code', 'insert_pair_brackets', 'highlight_selection_matches',
'brace_matching', 'sql_font_size', 'sql_font_ligatures',
'sql_font_family', 'indent_new_line'
],
'sql_formatting': [
'keyword_case', 'identifier_case', 'function_case',
'data_type_case', 'spaces_around_operators', 'tab_size',
'use_spaces', 'expression_width', 'logical_operator_new_line',
'lines_between_queries', 'new_line_before_semicolon'
]
}
category_ids = []
new_ids = []
pref_map = {}
# get metadata from current connection
meta = sa.MetaData()
# define table representation
meta.reflect(op.get_bind(), only=('user_preferences', 'module_preference',
'preference_category', 'preferences'))
module_pref_table = sa.Table('module_preference', meta)
module_id = session.query(ModulePreference).filter_by(
name='editor').first()
# Insert the 'editor' module in module_preference table
if not module_id:
op.execute(
module_pref_table.insert().values(name='editor')
)
module_id = session.query(ModulePreference).filter_by(
name='editor').first().id
# Insert the new preference categories in preference_category table
pref_category_table = sa.Table('preference_category', meta)
op.bulk_insert(pref_category_table, [
{'mid': module_id, 'name': 'keyboard_shortcuts'},
{'mid': module_id, 'name': 'sql_formatting'},
{'mid': module_id, 'name': 'options'},
])
# Insert the new preferences in preferences table
prefs_table = sa.Table('preferences', meta)
for category in new_pref_categories:
category_id = session.query(PreferenceCategory
).filter_by(name=category,
mid=module_id).first().id
op.bulk_insert(
prefs_table,
[
{'cid':category_id, 'name': pref_name}
for pref_name in preference_map[category]
]
)
# Migrate the preferences from 'sqleditor' module to 'editor'
category_data = session.query(ModulePreference, PreferenceCategory,).join(
PreferenceCategory).filter(
ModulePreference.name == 'sqleditor',
PreferenceCategory.name.in_(pref_categories)).all()
PreferenceCategory.name.in_(old_pref_categories)).all()
for module_data, pref_cat in category_data:
category_ids.append(pref_cat.id)
@@ -68,7 +119,7 @@ def upgrade():
new_data = session.query(ModulePreference, PreferenceCategory).join(
PreferenceCategory).filter(
ModulePreference.name == 'editor', PreferenceCategory.name.in_(
new_categories)).all()
new_pref_categories)).all()
for module_data, pref_cat in new_data:
new_ids.append(pref_cat.id)
@@ -84,15 +135,17 @@ def upgrade():
if pref.name == new_pref.name:
pref_map[pref.id] = new_pref.id
user_pref_table = sa.Table('user_preferences', meta)
# Update the user preferences with new preference ids
for key, val in pref_map.items():
record_to_update = session.query(UserPreference).filter_by(
pid=key).first()
if record_to_update:
record_to_update.pid = val
op.execute(
user_pref_table.update().where(
user_pref_table.c.pid == key).values(pid=val)
)
# Delete the old preferences and categories
session.query(Preferences).filter(Preferences.name.in_(prefs),
Preferences.cid.in_(category_ids)
session.query(Preferences).filter(Preferences.cid.in_(category_ids)
).delete(synchronize_session=False)
session.query(PreferenceCategory).filter(
+42
View File
@@ -0,0 +1,42 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2025, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""
Revision ID: efbbe5d5862f
Revises: e6ed5dac37c2
Create Date: 2025-09-29 18:40:30.248908
"""
from alembic import op, context
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'efbbe5d5862f'
down_revision = 'e6ed5dac37c2'
branch_labels = None
depends_on = None
def upgrade():
with op.batch_alter_table(
"server",
table_kwargs={'sqlite_autoincrement': True}) as batch_op:
batch_op.add_column(sa.Column('tunnel_prompt_password',
sa.Integer(), server_default='0'))
with op.batch_alter_table(
"sharedserver",
table_kwargs={'sqlite_autoincrement': True}) as batch_op:
batch_op.add_column(sa.Column('tunnel_prompt_password',
sa.Integer(), server_default='0'))
def downgrade():
# pgAdmin only upgrades, downgrade not implemented.
pass
+20 -20
View File
@@ -7,12 +7,12 @@
],
"license": "PostgreSQL",
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/core": "^7.28.3",
"@babel/eslint-parser": "^7.26.5",
"@babel/eslint-plugin": "^7.26.10",
"@babel/plugin-proposal-object-rest-spread": "^7.10.1",
"@babel/plugin-syntax-jsx": "^7.16.0",
"@babel/plugin-transform-runtime": "^7.27.4",
"@babel/plugin-transform-runtime": "^7.28.3",
"@babel/preset-env": "^7.28.0",
"@babel/preset-typescript": "^7.24.7",
"@emotion/memoize": "^0.9.0",
@@ -21,7 +21,7 @@
"@emotion/utils": "^1.0.0",
"@svgr/webpack": "^8.1.0",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/jest-dom": "^6.7.0",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^30.0.0",
@@ -30,21 +30,21 @@
"babel-loader": "^10.0.0",
"browserify": "^17.0.0",
"buffer": "^6.0.3",
"copy-webpack-plugin": "^13.0.0",
"copy-webpack-plugin": "^13.0.1",
"cross-env": "^10.0.0",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
"eslint": "^9.33.0",
"eslint": "^9.37.0",
"eslint-plugin-jest": "^29.0.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.1.4",
"eslint-plugin-unused-imports": "^4.2.0",
"exports-loader": "^5.0.0",
"globals": "^16.3.0",
"html-react-parser": "^5.2.0",
"image-minimizer-webpack-plugin": "^4.1.3",
"image-minimizer-webpack-plugin": "^4.1.4",
"imports-loader": "^5.0.0",
"jest": "^30.0.2",
"jest-environment-jsdom": "^30.0.4",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"loader-utils": "^3.2.1",
"mini-css-extract-plugin": "^2.9.2",
"postcss-loader": "^8.1.1",
@@ -58,7 +58,7 @@
"svgo-loader": "^4.0.0",
"terser-webpack-plugin": "^5.3.12",
"typescript": "^5.9.2",
"typescript-eslint": "^8.35.0",
"typescript-eslint": "^8.44.0",
"url-loader": "^4.1.1",
"webfonts-loader": "^8.0.1",
"webpack": "^5.101.0",
@@ -67,25 +67,26 @@
"yarn-audit-html": "7.3.2"
},
"optionalDependencies": {
"sharp": "^0.34.3"
"sharp": "^0.34.4"
},
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-react": "^7.12.13",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-sql": "^6.9.1",
"@codemirror/lang-sql": "^6.10.0",
"@date-io/core": "^3.0.0",
"@date-io/date-fns": "3.x",
"@emotion/sheet": "^1.0.1",
"@fluentui/keyboard-key": "^0.4.23",
"@fortawesome/fontawesome-free": "latest",
"@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1",
"@mui/x-date-pickers": "^8.10.0",
"@mui/icons-material": "^7.3.4",
"@mui/material": "^7.3.4",
"@mui/x-date-pickers": "^8.12.0",
"@nozbe/microfuzz": "^1.0.0",
"@projectstorm/react-diagrams": "^7.0.4",
"@simonwep/pickr": "^1.5.1",
"@szhsin/react-menu": "^4.4.1",
"@tanstack/react-query": "^5.84.2",
"@tanstack/react-query": "^5.87.1",
"@tanstack/react-table": "^8.16.0",
"@tanstack/react-virtual": "^3.13.6",
"@types/classnames": "^2.3.4",
@@ -98,11 +99,10 @@
"ajv": "^8.8.2",
"anti-trojan-source": "^1.4.0",
"aspen-decorations": "^1.0.2",
"axios": "^1.11.0",
"axios": "^1.12.0",
"babelify": "~10.0.0",
"bignumber.js": "^9.2.0",
"brace": "^0.11.1",
"browserfs": "^1.4.3",
"chart.js": "^4.4.7",
"chartjs-plugin-zoom": "^2.0.1",
"codemirror": "^6.0.1",
@@ -138,7 +138,7 @@
"react-frame-component": "^5.2.6",
"react-leaflet": "^4.2.1",
"react-new-window": "^1.0.1",
"react-resize-detector": "^12.1.0",
"react-resize-detector": "^12.3.0",
"react-rnd": "^10.5.1",
"react-select": "^5.7.2",
"react-timer-hook": "^4.0.1",
@@ -146,7 +146,7 @@
"snapsvg-cjs": "^0.0.6",
"socket.io-client": "^4.5.0",
"split.js": "^1.5.10",
"sql-formatter": "^15.6.2",
"sql-formatter": "^15.6.10",
"uplot": "^1.6.32",
"uplot-react": "^1.1.4",
"use-resize-observer": "^9.1.0",
@@ -18,16 +18,10 @@ LOWER_CASE_STR = gettext('Lower case')
PRESERVE_STR = gettext('Preserve')
def register_editor_preferences(self, migration_gettext=None):
def register_editor_preferences(self):
"""
Registers the editor preferences
"""
# migration_getttext is used once in case of migration
# In that case gettext will be used from migration_gettext
# instead of flask_babel gettext.
from flask_babel import gettext
if migration_gettext is not None:
gettext = migration_gettext
self.editor_preference = Preferences(
'editor', gettext('Editor')
@@ -58,13 +52,13 @@ def register_editor_preferences(self, migration_gettext=None):
gettext('Replace'),
'keyboardshortcut',
{
'alt': True,
'alt': False,
'shift': False,
'control': True,
'ctrl_is_meta': True,
'key': {
'key_code': 70,
'char': 'f'
'key_code': 82,
'char': 'r'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
@@ -167,6 +167,7 @@ class ServerModule(sg.ServerGroupPluginModule):
server.tunnel_password = sharedserver.tunnel_password
server.save_password = sharedserver.save_password
server.tunnel_identity_file = sharedserver.tunnel_identity_file
server.tunnel_prompt_password = sharedserver.tunnel_prompt_password
if hasattr(server, 'connection_params') and \
hasattr(sharedserver, 'connection_params') and \
'passfile' in server.connection_params and \
@@ -413,6 +414,7 @@ class ServerModule(sg.ServerGroupPluginModule):
tunnel_authentication=0,
tunnel_identity_file=None,
tunnel_keep_alive=0,
tunnel_prompt_password=0,
shared=True,
connection_params=data.connection_params,
prepare_threshold=data.prepare_threshold
@@ -790,6 +792,7 @@ class ServerNode(PGChildNodeView):
'tunnel_username': 'tunnel_username',
'tunnel_authentication': 'tunnel_authentication',
'tunnel_identity_file': 'tunnel_identity_file',
'tunnel_prompt_password': 'tunnel_prompt_password',
'tunnel_keep_alive': 'tunnel_keep_alive',
'shared': 'shared',
'shared_username': 'shared_username',
@@ -1086,6 +1089,8 @@ class ServerNode(PGChildNodeView):
'tunnel_username': tunnel_username,
'tunnel_identity_file': server.tunnel_identity_file
if server.tunnel_identity_file else None,
'tunnel_prompt_password': server.tunnel_prompt_password
if server.tunnel_identity_file else 0,
'tunnel_authentication': tunnel_authentication,
'tunnel_keep_alive': tunnel_keep_alive,
'kerberos_conn': bool(server.kerberos_conn),
@@ -1212,6 +1217,8 @@ class ServerNode(PGChildNodeView):
tunnel_authentication=1 if data.get('tunnel_authentication',
False) else 0,
tunnel_identity_file=data.get('tunnel_identity_file', None),
tunnel_prompt_password=1 if data.get('tunnel_prompt_password',
True) else 0,
tunnel_keep_alive=data.get('tunnel_keep_alive', 0),
shared=data.get('shared', None),
shared_username=data.get('shared_username', None),
@@ -1419,6 +1426,19 @@ class ServerNode(PGChildNodeView):
}
)
def is_prompt_tunnel_password(self, server):
"""
This function will check whether to prompt tunnel password or not.
"""
prompt_tunnel_password = True
# In case of identity file check the value of tunnel_prompt_password.
if server.tunnel_password is not None or \
(server.tunnel_identity_file is not None and
server.tunnel_prompt_password != 1):
prompt_tunnel_password = False
return prompt_tunnel_password
def connect(self, gid, sid, is_qt=False, server=None):
"""
Connect the Server and return the connection object.
@@ -1502,11 +1522,12 @@ class ServerNode(PGChildNodeView):
# If server using SSH Tunnel
if server.use_ssh_tunnel:
if 'tunnel_password' not in data:
if server.tunnel_password is None:
prompt_tunnel_password = True
else:
tunnel_password = server.tunnel_password
if 'tunnel_password' not in data and \
server.tunnel_password is None:
prompt_tunnel_password = self.is_prompt_tunnel_password(server)
elif 'tunnel_password' not in data and \
server.tunnel_password is not None:
tunnel_password = server.tunnel_password
else:
tunnel_password = data['tunnel_password'] \
if 'tunnel_password' in data else ''
@@ -1562,6 +1583,10 @@ class ServerNode(PGChildNodeView):
return self.get_response_for_password(
server, 428, prompt_password, prompt_tunnel_password)
# Check whether to prompt for the tunnel password in case if
# password is saved in server object or in data.
prompt_tunnel_password = self.is_prompt_tunnel_password(server)
try:
status, errmsg = conn.connect(
password=password,
@@ -1571,7 +1596,7 @@ class ServerNode(PGChildNodeView):
)
except Exception as e:
return self.get_response_for_password(
server, 401, True, True,
server, 401, not server.save_password, prompt_tunnel_password,
getattr(e, 'message', str(e)))
if not status:
@@ -1583,7 +1608,8 @@ class ServerNode(PGChildNodeView):
return internal_server_error(errmsg)
return self.get_response_for_password(
server, 401, True, True, errmsg)
server, 401, not server.save_password,
prompt_tunnel_password, errmsg)
else:
if save_password and config.ALLOW_SAVE_PASSWORD:
try:
@@ -37,6 +37,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
columns import utils as column_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
triggers import utils as trigger_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
utils import BaseTableView
class ForeignTableModule(SchemaChildModule):
@@ -102,7 +104,7 @@ class ForeignTableModule(SchemaChildModule):
blueprint = ForeignTableModule(__name__)
class ForeignTableView(PGChildNodeView, DataTypeReader,
class ForeignTableView(BaseTableView, DataTypeReader,
SchemaDiffObjectCompare):
"""
class ForeignTableView(PGChildNodeView)
@@ -187,6 +189,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
* compare(**kwargs):
- This function will compare the foreign table nodes from two different
schemas.
* truncate(gid, sid, scid, tid):
- This function will truncate foreign table object
"""
node_type = blueprint.node_type
@@ -211,6 +216,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
{'get': 'list', 'post': 'create', 'delete': 'delete'}
],
'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'truncate': [{'put': 'truncate'}],
'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}],
@@ -409,6 +415,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
self.template_path = \
self.BASE_TEMPLATE_PATH.format(self.manager.version)
self.table_template_path = compile_template_path(
'tables/sql', self.manager.version)
self.foreign_table_column_template_path = compile_template_path(
'foreign_table_columns/sql', self.manager.version)
@@ -884,6 +893,39 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def truncate(self, gid, sid, did, scid, foid):
"""
This function will truncate the foreign table.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
foid: Foreign Table ID
"""
try:
SQL = render_template(
"/".join([self.template_path, self._PROPERTIES_SQL]),
did=did, scid=scid, foid=foid,
datlastsysoid=self._DATABASE_LAST_SYSTEM_OID
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(gettext(self.not_found_error_msg()))
return super().truncate(
gid, sid, did, scid, foid, res
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def sql(self, gid, sid, did, scid, foid=None, **kwargs):
"""
@@ -12,6 +12,7 @@ import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.u
import ForeignTableSchema from './foreign_table.ui';
import _ from 'lodash';
import Notify from '../../../../../../../../static/js/helpers/Notifier';
import getApiInstance from '../../../../../../../../static/js/api_instance';
/* Create and Register Foreign Table Collection and Node. */
define('pgadmin.node.foreign_table', ['pgadmin.tables.js/enable_disable_triggers',
@@ -72,6 +73,21 @@ define('pgadmin.node.foreign_table', ['pgadmin.tables.js/enable_disable_triggers
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: gettext('Foreign Table...'),
data: {action: 'create', check: false}, enable: 'canCreate',
},{
name: 'truncate_foreign_table', node: 'foreign_table', module: this,
applies: ['object', 'context'], callback: 'truncate_foreign_table',
category: gettext('Truncate'), priority: 3, label: gettext('Truncate'),
enable : 'canCreate',
},{
name: 'truncate_foreign_table_cascade', node: 'foreign_table', module: this,
applies: ['object', 'context'], callback: 'truncate_foreign_table_cascade',
category: gettext('Truncate'), priority: 3, label: gettext('Truncate Cascade'),
enable : 'canCreate',
},{
name: 'truncate_foreign_table_identity', node: 'foreign_table', module: this,
applies: ['object', 'context'], callback: 'truncate_foreign_table_identity',
category: gettext('Truncate'), priority: 3, label: gettext('Truncate Restart Identity'),
enable : 'canCreate',
},{
// To enable/disable all triggers for the table
name: 'enable_all_triggers', node: 'foreign_table', module: this,
@@ -112,6 +128,56 @@ define('pgadmin.node.foreign_table', ['pgadmin.tables.js/enable_disable_triggers
args
);
},
/* Truncate foreign table */
truncate_foreign_table: function(args) {
let params = {'cascade': false };
this.callbacks.truncate.apply(this, [args, params]);
},
/* Truncate foreign table with cascade */
truncate_foreign_table_cascade: function(args) {
let params = {'cascade': true };
this.callbacks.truncate.apply(this, [args, params]);
},
/* Truncate foreign table with identity */
truncate_foreign_table_identity: function(args) {
let params = {'identity': true };
this.callbacks.truncate.apply(this, [args, params]);
},
truncate: function(args, params) {
let input = args || {},
obj = this,
t = pgBrowser.tree,
i = input.item || t.selected(),
d = i ? t.itemData(i) : undefined;
if (!d)
return false;
pgBrowser.notifier.confirm(
gettext('Truncate Foreign Table'),
gettext('Are you sure you want to truncate foreign table <b>%s</b>?', d.label),
function () {
let data = d;
getApiInstance().put(obj.generate_url(i, 'truncate' , d, true), params)
.then(({data: res})=>{
if (res.success == 1) {
pgBrowser.notifier.success(res.info);
t.removeIcon(i);
data.icon = data.is_partitioned ? 'icon-partition': 'icon-table';
t.addIcon(i, {icon: data.icon});
t.updateAndReselectNode(i, data);
}
if (res.success == 2) {
pgBrowser.notifier.error(res.info);
}
})
.catch((error)=>{
pgBrowser.notifier.pgRespErrorNotify(error);
t.refresh(i);
});
}, function() {/*This is intentional (SonarQube)*/}
);
},
},
// Check to whether table has disable trigger(s)
canCreate_with_trigger_enable: function(itemData) {
@@ -260,7 +260,7 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
list_params = []
if request.method == 'GET':
list_params = ['arguments', 'variables', 'proacl',
'seclabels', 'acl', 'args']
'seclabels', 'acl', 'args', 'dependsonextensions']
if key in list_params and req[key] != '' and req[key] is not None:
# Coverts string into python list as expected.
@@ -1171,6 +1171,12 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
old_data['proparallel'] = \
parallel_dict[old_data['proparallel']]
if self.node_type == 'function':
old_data['dependsonextensions'] = \
old_data.get('dependsonextensions') or []
data['dependsonextensions'] = \
data.get('dependsonextensions') or []
# If any of the below argument is changed,
# then CREATE OR REPLACE SQL statement should be called
fun_change_args = ['lanname', 'prosrc', 'probin', 'prosrc_c',
@@ -76,6 +76,7 @@ define('pgadmin.node.function', [
},
getSchema: function(treeNodeInfo, itemNodeData) {
let nodeObj = pgBrowser.Nodes['extension'];
return new FunctionSchema(
(privileges)=>getNodePrivilegeRoleSchema(this, treeNodeInfo, itemNodeData, privileges),
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
@@ -85,6 +86,16 @@ define('pgadmin.node.function', [
cacheLevel: 'database'
}
),
extensionsList:()=>getNodeAjaxOptions('nodes', nodeObj, treeNodeInfo, itemNodeData, { cacheLevel: 'server'},
(data)=>{
let res = [];
if (data && _.isArray(data)) {
_.each(data, function(d) {
res.push({label: d.label, value: d.label, data: d});
});
}
return res;
}),
getTypes: ()=>getNodeAjaxOptions('get_types', this, treeNodeInfo, itemNodeData),
getLanguage: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData),
getSupportFunctions: ()=>getNodeAjaxOptions('get_support_functions', this, treeNodeInfo, itemNodeData, {
@@ -137,6 +137,7 @@ export default class FunctionSchema extends BaseUISchema {
role: [],
schema: [],
getTypes: [],
extensionsList: [],
...fieldOptions,
};
}
@@ -274,8 +275,22 @@ export default class FunctionSchema extends BaseUISchema {
return this.node_info && 'catalog' in this.node_info;
}
},
{
},{
id: 'dependsonextensions',
label: gettext('Depends on extensions'),
group: gettext('Definition'),
type: 'select',
options: this.fieldOptions.extensionsList,
controlProps: {
multiple: true,
allowClear: true,
allowSelectAll: true,
placeholder: gettext('Select the Depends on extensions...'),
},
min_version: 130000,
mode: ['create', 'edit', 'properties'],
visible: obj.isVisible
},{
id: 'probin', label: gettext('Object file'), cell: 'string',
type: 'text', group: gettext('Definition'), deps: ['lanname'], visible:
function(state) {
@@ -0,0 +1,82 @@
{% import 'macros/functions/security.macros' as SECLABEL %}
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
{% import 'macros/functions/variable.macros' as VARIABLE %}
{% set is_columns = [] %}
{% set exclude_quoting = ['search_path'] %}
{% if data %}
{% if query_for == 'sql_panel' and func_def is defined %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{func_def}}
{% else %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %}
{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{ p.argtype }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %}, {% endif %}
{% endfor %}
{% endif -%}
)
{% endif %}
RETURNS{% if data.proretset and (data.prorettypename.startswith('SETOF ') or data.prorettypename.startswith('TABLE')) %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }}
{% if data.procost %}
COST {{data.procost}}
{% endif %}
{% if data.provolatile %}{% if data.provolatile == 'i' %}IMMUTABLE{% elif data.provolatile == 's' %}STABLE{% else %}VOLATILE{% endif %} {% endif %}{% if data.proleakproof %}LEAKPROOF {% endif %}
{% if data.proisstrict %}STRICT {% endif %}
{% if data.prosecdef %}SECURITY DEFINER {% endif %}
{% if data.proiswindow %}WINDOW {% endif %}
{% if data.proparallel and (data.proparallel == 'r' or data.proparallel == 's' or data.proparallel == 'u') %}
{% if data.proparallel == 'r' %}PARALLEL RESTRICTED {% elif data.proparallel == 's' %}PARALLEL SAFE {% elif data.proparallel == 'u' %}PARALLEL UNSAFE{% endif %}{% endif %}
{% if data.prorows and (data.prorows | int) > 0 %}
ROWS {{data.prorows}}
{% endif %}
{% if data.prosupportfunc %}
SUPPORT {{ data.prosupportfunc }}
{% endif -%}
{% if data.variables %}{% for v in data.variables %}
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor %}
{% endif %}
AS {% if data.lanname == 'c' %}
{{ data.probin|qtLiteral(conn) }}, {{ data.prosrc_c|qtLiteral(conn) }}
{% else %}
$BODY${{ data.prosrc }}$BODY${% endif -%};
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}
{% if data.acl %}
{% for p in data.acl %}
{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args_without)}}
{% endfor %}{% endif %}
{% if data.revoke_all %}
{{ PRIVILEGE.UNSETALL(conn, "FUNCTION", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
{% endif %}
{% if data.description %}
COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
IS {{ data.description|qtLiteral(conn) }};
{% endif -%}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.label and r.provider %}
{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data.pronamespace, data.func_args_without) }}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}
@@ -0,0 +1,49 @@
SELECT
pr.oid, pr.xmin,
CASE WHEN pr.prokind = 'w' THEN true ELSE false END AS proiswindow,
pr.prosrc, pr.prosrc AS prosrc_c, pr.pronamespace, pr.prolang, pr.procost, pr.prorows, pr.prokind,
pr.prosecdef, pr.proleakproof, pr.proisstrict, pr.proretset, pr.provolatile, pr.proparallel,
pr.pronargs, pr.prorettype, pr.proallargtypes, pr.proargmodes, pr.probin, pr.proacl,
pr.proname, pr.proname AS name, pg_catalog.pg_get_function_result(pr.oid) AS prorettypename,
typns.nspname AS typnsp, lanname, proargnames, pg_catalog.oidvectortypes(proargtypes) AS proargtypenames,
pg_catalog.pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
CASE WHEN prosupport = 0::oid THEN ''
ELSE (
SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname) AS tfunctions
FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n
WHERE p.pronamespace = n.oid
AND p.oid = pr.prosupport::OID
) END AS prosupportfunc,
(SELECT
pg_catalog.array_agg(provider || '=' || label)
FROM
pg_catalog.pg_seclabel sl1
WHERE
sl1.objoid=pr.oid) AS seclabels
FROM
pg_catalog.pg_proc pr
JOIN
pg_catalog.pg_type typ ON typ.oid=prorettype
JOIN
pg_catalog.pg_namespace typns ON typns.oid=typ.typnamespace
JOIN
pg_catalog.pg_language lng ON lng.oid=prolang
LEFT OUTER JOIN
pg_catalog.pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass and des.objsubid = 0)
WHERE
pr.prokind IN ('f', 'w')
AND typname NOT IN ('trigger', 'event_trigger')
{% if fnid %}
AND pr.oid = {{fnid}}::oid
{% else %}
AND pronamespace = {{scid}}::oid
{% endif %}
ORDER BY
proname;
@@ -0,0 +1,146 @@
{% import 'macros/functions/security.macros' as SECLABEL %}
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %}
{% set name = o_data.name %}
{% set exclude_quoting = ['search_path'] %}
{% set set_variables = [] %}
{% if 'merged_variables' in data and data.merged_variables|length > 0 %}
{% set set_variables = data.merged_variables %}
{% elif 'variables' in o_data and o_data.variables|length > 0 %}
{% set set_variables = o_data.variables %}
{% endif %}
{% if data.name %}
{% if data.name != o_data.name %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{
o_data.proargtypenames }})
RENAME TO {{ conn|qtIdent(data.name) }};
{% set name = data.name %}
{% endif %}
{% endif -%}
{% if data.change_func %}
CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %}
{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{ p.argtype }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %},{% endif %}
{% endfor %}
{% endif -%}
)
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
{% if 'lanname' in data %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }} {% else %}
LANGUAGE {{ o_data.lanname|qtLiteral(conn) }}
{% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %}
{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %}
{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %}
{% 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 '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 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.prosupportfunc %}SUPPORT {{ data.prosupportfunc }}{% elif data.prosupportfunc is not defined and o_data.prosupportfunc %}SUPPORT {{ o_data.prosupportfunc }}{% endif -%}{% if set_variables and set_variables|length > 0 %}{% for v in set_variables %}
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
{% endif %}
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
{% if 'probin' in data %}{{ data.probin|qtLiteral(conn) }}{% else %}{{ o_data.probin|qtLiteral(conn) }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral(conn) }}{% else %}{{ o_data.prosrc_c|qtLiteral(conn) }}{% endif %}{% elif 'prosrc' in data %}
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
{{ o_data.probin|qtLiteral(conn) }}, {{ o_data.prosrc_c|qtLiteral(conn) }}{% else %}
$BODY${{ o_data.prosrc }}$BODY${% endif -%};
{% endif -%}
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{# The SQL generated below will change priviledges #}
{% if data.acl %}
{% if 'deleted' in data.acl %}
{% for priv in data.acl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'changed' in data.acl %}
{% for priv in data.acl.changed %}
{% if priv.grantee != priv.old_grantee %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.old_grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% else %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% endif %}
{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'added' in data.acl %}
{% for priv in data.acl.added %}
{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}{% endif -%}
{% endif -%}
{% if data.change_func == False %}
{% if data.variables %}
{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %}
{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }}
{% endif -%}
{% if 'merged_variables' in data and data.merged_variables|length > 0 %}
{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }}
{% endif -%}
{% endif -%}
{% endif -%}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if data.description is defined and data.description != o_data.description%}
COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
IS {{ data.description|qtLiteral(conn) }};
{% endif -%}
{% if data.pronamespace %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}
{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}
{% if ext in new_exts and ext not in old_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
@@ -50,6 +50,15 @@ $BODY${{ data.prosrc }}$BODY${% endif -%};
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}
{% if data.acl %}
{% for p in data.acl %}
@@ -10,6 +10,12 @@ SELECT
pg_catalog.pg_get_function_sqlbody(pr.oid) AS prosrc_sql,
CASE WHEN pr.prosqlbody IS NOT NULL THEN true ELSE false END as is_pure_sql,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
CASE WHEN prosupport = 0::oid THEN ''
ELSE (
SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname) AS tfunctions
@@ -130,4 +130,20 @@ ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtype
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}
{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}
{% if ext in new_exts and ext not in old_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
@@ -0,0 +1,83 @@
{% import 'macros/functions/security.macros' as SECLABEL %}
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
{% import 'macros/functions/variable.macros' as VARIABLE %}
{% set is_columns = [] %}
{% set exclude_quoting = ['search_path'] %}
{% if data %}
{% if query_for == 'sql_panel' and func_def is defined %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{func_def}}
{% else %}
CREATE{% if query_type is defined %}{{' OR REPLACE'}}{% endif %} FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.arguments %}
{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{ p.argtype }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %}, {% endif %}
{% endfor %}
{% endif -%}
)
{% endif %}
RETURNS{% if data.proretset and (data.prorettypename.startswith('SETOF ') or data.prorettypename.startswith('TABLE')) %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }}
{% if data.procost %}
COST {{data.procost}}
{% endif %}
{% if data.provolatile %}{% if data.provolatile == 'i' %}IMMUTABLE{% elif data.provolatile == 's' %}STABLE{% else %}VOLATILE{% endif %} {% endif %}{% if data.proleakproof %}LEAKPROOF {% endif %}
{% if data.proisstrict %}STRICT {% endif %}
{% if data.prosecdef %}SECURITY DEFINER {% endif %}
{% if data.proiswindow %}WINDOW {% endif %}
{% if data.proparallel and (data.proparallel == 'r' or data.proparallel == 's' or data.proparallel == 'u') %}
{% if data.proparallel == 'r' %}PARALLEL RESTRICTED {% elif data.proparallel == 's' %}PARALLEL SAFE {% elif data.proparallel == 'u' %}PARALLEL UNSAFE{% endif %}{% endif %}
{% if data.prorows and (data.prorows | int) > 0 %}
ROWS {{data.prorows}}
{% endif %}
{% if data.prosupportfunc %}
SUPPORT {{ data.prosupportfunc }}
{% endif -%}
{% if data.variables %}{% for v in data.variables %}
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor %}
{% endif %}
AS {% if data.lanname == 'c' %}
{{ data.probin|qtLiteral(conn) }}, {{ data.prosrc_c|qtLiteral(conn) }}
{% else %}
$BODY${{ data.prosrc }}$BODY${% endif -%};
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}
{% if data.acl %}
{% for p in data.acl %}
{{ PRIVILEGE.SET(conn, "FUNCTION", p.grantee, data.name, p.without_grant, p.with_grant, data.pronamespace, data.func_args_without)}}
{% endfor %}{% endif %}
{% if data.revoke_all %}
{{ PRIVILEGE.UNSETALL(conn, "FUNCTION", "PUBLIC", data.name, data.pronamespace, data.func_args_without)}}
{% endif %}
{% if data.description %}
COMMENT ON FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
IS {{ data.description|qtLiteral(conn) }};
{% endif -%}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.label and r.provider %}
{{ SECLABEL.SET(conn, 'FUNCTION', data.name, r.provider, r.label, data.pronamespace, data.func_args_without) }}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}
@@ -0,0 +1,43 @@
SELECT
pr.oid, pr.xmin,
CASE WHEN pr.prokind = 'w' THEN true ELSE false END AS proiswindow,
pr.prosrc, pr.prosrc AS prosrc_c, pr.pronamespace, pr.prolang, pr.procost, pr.prorows, pr.prokind,
pr.prosecdef, pr.proleakproof, pr.proisstrict, pr.proretset, pr.provolatile, pr.proparallel,
pr.pronargs, pr.prorettype, pr.proallargtypes, pr.proargmodes, pr.probin, pr.proacl,
pr.proname, pr.proname AS name, pg_catalog.pg_get_function_result(pr.oid) AS prorettypename,
typns.nspname AS typnsp, lanname, proargnames, pg_catalog.oidvectortypes(proargtypes) AS proargtypenames,
pg_catalog.pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
CASE WHEN prosupport = 0::oid THEN '' ELSE prosupport::text END AS prosupportfunc,
(SELECT
pg_catalog.array_agg(provider || '=' || label)
FROM
pg_catalog.pg_seclabel sl1
WHERE
sl1.objoid=pr.oid) AS seclabels
FROM
pg_catalog.pg_proc pr
JOIN
pg_catalog.pg_type typ ON typ.oid=prorettype
JOIN
pg_catalog.pg_namespace typns ON typns.oid=typ.typnamespace
JOIN
pg_catalog.pg_language lng ON lng.oid=prolang
LEFT OUTER JOIN
pg_catalog.pg_description des ON (des.objoid=pr.oid AND des.classoid='pg_proc'::regclass and des.objsubid = 0)
WHERE
pr.prokind IN ('f', 'w')
AND typname NOT IN ('trigger', 'event_trigger')
{% if fnid %}
AND pr.oid = {{fnid}}::oid
{% else %}
AND pronamespace = {{scid}}::oid
{% endif %}
ORDER BY
proname;
@@ -0,0 +1,146 @@
{% import 'macros/functions/security.macros' as SECLABEL %}
{% import 'macros/functions/privilege.macros' as PRIVILEGE %}
{% import 'macros/functions/variable.macros' as VARIABLE %}{% if data %}
{% set name = o_data.name %}
{% set exclude_quoting = ['search_path'] %}
{% set set_variables = [] %}
{% if 'merged_variables' in data and data.merged_variables|length > 0 %}
{% set set_variables = data.merged_variables %}
{% elif 'variables' in o_data and o_data.variables|length > 0 %}
{% set set_variables = o_data.variables %}
{% endif %}
{% if data.name %}
{% if data.name != o_data.name %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, o_data.name) }}({{
o_data.proargtypenames }})
RENAME TO {{ conn|qtIdent(data.name) }};
{% set name = data.name %}
{% endif %}
{% endif -%}
{% if data.change_func %}
CREATE OR REPLACE FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({% if data.arguments %}
{% for p in data.arguments %}{% if p.argmode %}{{p.argmode}} {% endif %}{% if p.argname %}{{ conn|qtIdent(p.argname) }} {% endif %}{% if p.argtype %}{{ p.argtype }}{% endif %}{% if p.argdefval %} DEFAULT {{p.argdefval}}{% endif %}
{% if not loop.last %},{% endif %}
{% endfor %}
{% endif -%}
)
RETURNS {% if 'prorettypename' in data %}{{ data.prorettypename }}{% else %}{{ o_data.prorettypename }}{% endif %}
{% if 'lanname' in data %}
LANGUAGE {{ data.lanname|qtLiteral(conn) }} {% else %}
LANGUAGE {{ o_data.lanname|qtLiteral(conn) }}
{% endif %}{% if 'provolatile' in data and data.provolatile %}{{ data.provolatile }} {% elif 'provolatile' not in data and o_data.provolatile %}{{ o_data.provolatile }}{% endif %}
{% if ('proleakproof' in data and data.proleakproof) or ('proleakproof' not in data and o_data.proleakproof) %} LEAKPROOF{% elif 'proleakproof' in data and not data.proleakproof %} NOT LEAKPROOF{% endif %}
{% if ('proisstrict' in data and data.proisstrict) or ('proisstrict' not in data and o_data.proisstrict) %} STRICT{% endif %}
{% 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 '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 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.prosupportfunc %}SUPPORT {{ data.prosupportfunc }}{% elif data.prosupportfunc is not defined and o_data.prosupportfunc %}SUPPORT {{ o_data.prosupportfunc }}{% endif -%}{% if set_variables and set_variables|length > 0 %}{% for v in set_variables %}
SET {{ conn|qtIdent(v.name) }}={% if v.name in exclude_quoting %}{{ v.value }}{% else %}{{ v.value|qtLiteral(conn) }}{% endif %}{% endfor -%}
{% endif %}
AS {% if (data.lanname == 'c' or o_data.lanname == 'c') and ('probin' in data or 'prosrc_c' in data) %}
{% if 'probin' in data %}{{ data.probin|qtLiteral(conn) }}{% else %}{{ o_data.probin|qtLiteral(conn) }}{% endif %}, {% if 'prosrc_c' in data %}{{ data.prosrc_c|qtLiteral(conn) }}{% else %}{{ o_data.prosrc_c|qtLiteral(conn) }}{% endif %}{% elif 'prosrc' in data %}
$BODY${{ data.prosrc }}$BODY${% elif o_data.lanname == 'c' %}
{{ o_data.probin|qtLiteral(conn) }}, {{ o_data.prosrc_c|qtLiteral(conn) }}{% else %}
$BODY${{ o_data.prosrc }}$BODY${% endif -%};
{% endif -%}
{% if data.funcowner %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{# The SQL generated below will change priviledges #}
{% if data.acl %}
{% if 'deleted' in data.acl %}
{% for priv in data.acl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'changed' in data.acl %}
{% for priv in data.acl.changed %}
{% if priv.grantee != priv.old_grantee %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.old_grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% else %}
{{ PRIVILEGE.UNSETALL(conn, 'FUNCTION', priv.grantee, name, o_data.pronamespace, o_data.proargtypenames) }}
{% endif %}
{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'added' in data.acl %}
{% for priv in data.acl.added %}
{{ PRIVILEGE.SET(conn, 'FUNCTION', priv.grantee, name, priv.without_grant, priv.with_grant, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}{% endif -%}
{% endif -%}
{% if data.change_func == False %}
{% if data.variables %}
{% if 'deleted' in data.variables and data.variables.deleted|length > 0 %}
{{ VARIABLE.UNSET(conn, 'FUNCTION', name, data.variables.deleted, o_data.pronamespace, o_data.proargtypenames) }}
{% endif -%}
{% if 'merged_variables' in data and data.merged_variables|length > 0 %}
{{ VARIABLE.SET(conn, 'FUNCTION', name, data.merged_variables, o_data.pronamespace, o_data.proargtypenames) }}
{% endif -%}
{% endif -%}
{% endif -%}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.UNSET(conn, 'FUNCTION', name, r.provider, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.SET(conn, 'FUNCTION', name, r.provider, r.label, o_data.pronamespace, o_data.proargtypenames) }}
{% endfor %}
{% endif -%}
{% if data.description is defined and data.description != o_data.description%}
COMMENT ON FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
IS {{ data.description|qtLiteral(conn) }};
{% endif -%}
{% if data.pronamespace %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtypenames }})
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}
{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}
{% if ext in new_exts and ext not in old_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
@@ -50,6 +50,15 @@ $BODY${{ data.prosrc }}$BODY${% endif -%};
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
OWNER TO {{ conn|qtIdent(data.funcowner) }};
{% endif -%}
{% if data.dependsonextensions %}
{% for ext in data.dependsonextensions %}
ALTER FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({{data.func_args_without}})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endfor %}
{% endif %}
{% if data.acl %}
{% for p in data.acl %}
@@ -8,6 +8,12 @@ SELECT
typns.nspname AS typnsp, lanname, proargnames, pg_catalog.oidvectortypes(proargtypes) AS proargtypenames,
pg_catalog.pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS proargdefaultvals,
pr.pronargdefaults, proconfig, pg_catalog.pg_get_userbyid(proowner) AS funcowner, description,
(
SELECT array_agg(DISTINCT e.extname)
FROM pg_depend d
JOIN pg_extension e ON d.refobjid = e.oid
WHERE d.objid = pr.oid
) AS dependsonextensions,
pg_catalog.pg_get_function_sqlbody(pr.oid) AS prosrc_sql,
CASE WHEN pr.prosqlbody IS NOT NULL THEN true ELSE false END as is_pure_sql,
CASE WHEN prosupport = 0::oid THEN '' ELSE prosupport::text END AS prosupportfunc,
@@ -130,4 +130,20 @@ ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{o_data.proargtype
SET SCHEMA {{ conn|qtIdent(data.pronamespace) }};
{% endif -%}
{% set old_exts = (o_data.dependsonextensions or []) | list %}
{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %}
{% if new_exts is not none and old_exts != new_exts %}
{% for ext in (old_exts + new_exts) | unique %}
{% if ext in new_exts and ext not in old_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% elif ext in old_exts and ext not in new_exts %}
ALTER FUNCTION {{ conn|qtIdent(o_data.pronamespace, name) }}({{ o_data.proargtypenames }})
NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }};
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
@@ -0,0 +1,2 @@
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
NO DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,22 @@
-- FUNCTION: public.Function1_$%{}[]()&*^!@"'`\/#(character varying)
-- DROP FUNCTION IF EXISTS public."Function1_$%{}[]()&*^!@""'`\/#"(character varying);
CREATE OR REPLACE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(
param character varying DEFAULT '1'::character varying)
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort='true'
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO postgres;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
@@ -0,0 +1,20 @@
CREATE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(IN param character varying DEFAULT '1')
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort=true
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO postgres;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,25 @@
-- FUNCTION: public.Function1_$%{}[]()&*^!@"'`\/#(character varying)
-- DROP FUNCTION IF EXISTS public."Function1_$%{}[]()&*^!@""'`\/#"(character varying);
CREATE OR REPLACE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(
param character varying DEFAULT '1'::character varying)
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort='true'
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO postgres;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,434 @@
{
"scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
}
},
{
"type": "create",
"name": "Create function with extensions.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"dependsonextensions": ["plpgsql", "postgres_fdw"],
"schema": "public"
},
"expected_sql_file": "create_function_on_depends.sql",
"expected_msql_file": "create_function_on_depends.msql"
},
{
"type": "alter",
"name": "Alter function with NO DEPENDS ON",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_function_no_depends.sql",
"expected_msql_file": "alter_function_no_depends.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function with all options.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function.sql",
"expected_msql_file": "create_function.msql"
},
{
"type": "alter",
"name": "Alter function comment",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"description": "Some comment"
},
"expected_sql_file": "alter_function_comment.sql",
"expected_msql_file": "alter_function_comment.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for alter.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function rename.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name":"Function3_$%{}[]()&*^!@\"'`\\/#"
},
"expected_sql_file": "alter_function_rename.sql",
"expected_msql_file": "alter_function_rename.msql"
},
{
"type": "alter",
"name": "Alter function code and add parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"prosrc": "begin\nselect '2';\nend\n",
"variables": {
"added": [
{
"name": "application_name",
"value": "appname"
}
]
}
},
"expected_sql_file": "alter_function_add_parameter.sql",
"expected_msql_file": "alter_function_add_parameter.msql"
},
{
"type": "alter",
"name": "Alter function delete parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"variables": {
"deleted": [
{
"name": "application_name",
"value": true
}
]
}
},
"expected_sql_file": "alter_function_delete_parameter.sql",
"expected_msql_file": "alter_function_delete_parameter.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for acl.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function add acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_add_acl.sql",
"expected_msql_file": "alter_function_add_acl.msql"
},
{
"type": "alter",
"name": "Alter function remove partial privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter function change grantee in privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"old_grantee": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_change_grantee_acl.sql",
"expected_msql_file": "alter_function_change_grantee_acl.msql"
},
{
"type": "alter",
"name": "Alter function delete acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_delete_acl.sql",
"expected_msql_file": "alter_function_delete_acl.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"name": "Create function with custom return type.",
"data": {
"name": "Function3_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "table(val character varying)",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\n return query select '1'::character varying;\nend",
"probin": "$libdir/",
"options": [],
"variables": [],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_with_custom_return.sql",
"expected_msql_file": "create_function_with_custom_return.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
}
]
}
@@ -1,5 +1,81 @@
{
"scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
}
},
{
"type": "create",
"name": "Create function with extensions.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"dependsonextensions": ["plpgsql", "postgres_fdw"],
"schema": "public"
},
"expected_sql_file": "create_function_on_depends.sql",
"expected_msql_file": "create_function_on_depends.msql"
},
{
"type": "alter",
"name": "Alter function with NO DEPENDS ON",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_function_no_depends.sql",
"expected_msql_file": "alter_function_no_depends.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function with all options.",
@@ -0,0 +1,2 @@
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
NO DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,22 @@
-- FUNCTION: public.Function1_$%{}[]()&*^!@"'`\/#(character varying)
-- DROP FUNCTION IF EXISTS public."Function1_$%{}[]()&*^!@""'`\/#"(character varying);
CREATE OR REPLACE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(
param character varying DEFAULT '1'::character varying)
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort='true'
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO enterprisedb;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
@@ -0,0 +1,20 @@
CREATE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(IN param character varying DEFAULT '1')
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort=true
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO enterprisedb;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,25 @@
-- FUNCTION: public.Function1_$%{}[]()&*^!@"'`\/#(character varying)
-- DROP FUNCTION IF EXISTS public."Function1_$%{}[]()&*^!@""'`\/#"(character varying);
CREATE OR REPLACE FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(
param character varying DEFAULT '1'::character varying)
RETURNS character varying
LANGUAGE 'plpgsql'
COST 100
VOLATILE LEAKPROOF STRICT SECURITY DEFINER WINDOW PARALLEL UNSAFE
SET enable_sort='true'
AS $BODY$
begin
select '1';
end
$BODY$;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
OWNER TO enterprisedb;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION plpgsql;
ALTER FUNCTION public."Function1_$%{}[]()&*^!@""'`\/#"(character varying)
DEPENDS ON EXTENSION postgres_fdw;
@@ -0,0 +1,446 @@
{
"scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
}
},
{
"type": "create",
"name": "Create function with extensions.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"dependsonextensions": ["plpgsql", "postgres_fdw"],
"schema": "public"
},
"expected_sql_file": "create_function_on_depends.sql",
"expected_msql_file": "create_function_on_depends.msql"
},
{
"type": "alter",
"name": "Alter function with NO DEPENDS ON",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_function_no_depends.sql",
"expected_msql_file": "alter_function_no_depends.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function with all options.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function.sql",
"expected_msql_file": "create_function.msql"
},
{
"type": "alter",
"name": "Alter function comment",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"description": "Some comment"
},
"expected_sql_file": "alter_function_comment.sql",
"expected_msql_file": "alter_function_comment.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for alter.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"prosecdef": true,
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function rename.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function3_$%{}[]()&*^!@\"'`\\/#"
},
"expected_sql_file": "alter_function_rename.sql",
"expected_msql_file": "alter_function_rename.msql"
},
{
"type": "alter",
"name": "Alter function code and add parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"prosrc": "begin\nselect '2';\nend\n",
"variables": {
"added": [
{
"name": "application_name",
"value": "appname"
}
]
}
},
"expected_sql_file": "alter_function_add_parameter.sql"
},
{
"type": "alter",
"name": "Alter function delete parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"variables": {
"deleted": [
{
"name": "application_name",
"value": true
}
]
}
},
"expected_sql_file": "alter_function_delete_parameter.sql",
"expected_msql_file": "alter_function_delete_parameter.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for acl.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"prosecdef": true,
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function add acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_add_acl.sql",
"expected_msql_file": "alter_function_add_acl.msql"
},
{
"type": "alter",
"name": "Alter function remove partial privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter function change grantee in privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"old_grantee": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_change_grantee_acl.sql",
"expected_msql_file": "alter_function_change_grantee_acl.msql"
},
{
"type": "alter",
"name": "Alter function delete acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_delete_acl.sql",
"expected_msql_file": "alter_function_delete_acl.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"name": "Create function with custom return type.",
"data": {
"name": "Function3_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "table(val character varying)",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\n return query select '1'::character varying;\nend",
"probin": "$libdir/",
"options": [],
"variables": [],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_with_custom_return.sql",
"expected_msql_file": "create_function_with_custom_return.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
}
]
}
@@ -1,5 +1,81 @@
{
"scenarios": [
{
"type": "create",
"name": "Create Extension",
"endpoint": "NODE-extension.obj",
"sql_endpoint": "NODE-extension.sql_id",
"data": {
"name": "postgres_fdw",
"version": "",
"relocatable": true
}
},
{
"type": "create",
"name": "Create function with extensions.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"dependsonextensions": ["plpgsql", "postgres_fdw"],
"schema": "public"
},
"expected_sql_file": "create_function_on_depends.sql",
"expected_msql_file": "create_function_on_depends.msql"
},
{
"type": "alter",
"name": "Alter function with NO DEPENDS ON",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"dependsonextensions": ["plpgsql"]
},
"expected_sql_file": "alter_function_no_depends.sql",
"expected_msql_file": "alter_function_no_depends.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function with all options.",
@@ -76,6 +76,19 @@ class FunctionAddTestCase(BaseTestGenerator):
"status_code": 500
}
)),
('Create Function With Invalid Depends On Extension Fail', dict(
url='/browser/function/obj/',
is_positive_test=False,
mocking_required=True,
is_mock_function=True,
mock_data={
"function_name": "_get_sql",
"return_value": "(False, 'Invalid extension specified')"
},
expected_data={
"status_code": 500
}
))
]
def create_function(self, data):
@@ -113,6 +126,7 @@ class FunctionAddTestCase(BaseTestGenerator):
"lanname": "sql",
"name": "test_function",
"options": [],
"dependsonextensions": ["plpgsql"],
"proleakproof": True,
"pronamespace": 2200,
"prorettypename": "integer",
@@ -143,10 +157,13 @@ class FunctionAddTestCase(BaseTestGenerator):
)
data['prosupportfuc'] = support_function_name
if self.is_positive_test:
response = self.create_function(data)
else:
if "Invalid Depends On Extension" in getattr(
self, 'scenario_name', ''
):
data["dependsonextensions"] = ["non_existing_extensions"]
if hasattr(self, 'is_mock_function'):
def _get_sql(self, **kwargs):
return False, ''
@@ -35,6 +35,7 @@ class FunctionGetmsqlTestCase(BaseTestGenerator):
"funcowner": "",
"pronamespace": 2200,
"prorettypename": "character varying",
"dependsonextensions": [],
"lanname": "sql",
"arguments": [],
"prosrc": "select '1'",
@@ -67,7 +68,8 @@ class FunctionGetmsqlTestCase(BaseTestGenerator):
"probin": "$libdir/",
"variables": [],
"seclabels": [],
"acl": []
"acl": [],
"dependsonextensions": ["non_existing_extension"]
},
mock_data={
"function_name": '_get_sql',
@@ -178,7 +180,6 @@ class FunctionGetmsqlTestCase(BaseTestGenerator):
func_name = "test_function_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name)
func_id = function_info[0]
self.test_data['oid'] = func_id
self.test_data['name'] = func_name
@@ -187,6 +188,7 @@ class FunctionGetmsqlTestCase(BaseTestGenerator):
self.schema_id) + '/' + str(func_id) + '?' + (
urlencode(self.test_data))
else:
self.test_data['dependsonextensions'] = json.dumps(["plpgsql"])
url = self.url + str(utils.SERVER_GROUP) + '/' + str(
self.server_id) + '/' + str(self.db_id) + '/' + str(
self.schema_id) + '/?' + (urlencode(self.test_data))
@@ -75,7 +75,7 @@ class FunctionPutTestCase(BaseTestGenerator):
}
)),
(
'Fetch Function update with arguments',
'Fetch Function update with arguments and depends on exxtensions.',
dict(
url='/browser/function/obj/',
is_positive_test=True,
@@ -155,7 +155,8 @@ class FunctionPutTestCase(BaseTestGenerator):
data = {
"description": "This is a procedure update comment",
"id": func_id
"id": func_id,
"dependsonextensions": ["plpgsql"]
}
if hasattr(self, "is_add_argument") and self.is_add_argument:
@@ -13,7 +13,7 @@
add empty bracket with table name
#}
{% set empty_bracket = ""%}
{% if data.coll_inherits|length == 0 and data.columns|length == 0 and not data.typname and not data.like_relation and data.primary_key|length == 0 and data.unique_constraint|length == 0 and data.foreign_key|length == 0 and data.check_constraint|length == 0 and data.exclude_constraint|length == 0 %}
{% if not (data.coll_inherits or data.columns or data.typname or data.like_relation or data.primary_key or data.unique_constraint or data.foreign_key or data.check_constraint or data.exclude_constraint) %}
{% set empty_bracket = "\n(\n)"%}
{% endif %}
{% set with_clause = false%}
@@ -249,6 +249,15 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
return wrap
def has_dependent_type(self, data):
"""
This function is used to check the type has dependent
on another type.
"""
return ('rngmultirangetype' in data and
data['rngmultirangetype'] is not None and
data['rngmultirangetype'] != '')
@check_precondition
def list(self, gid, sid, did, scid):
"""
@@ -317,7 +326,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
rset['rows'][0]['oid'],
scid,
rset['rows'][0]['name'],
icon=self.icon_str % self.node_type
icon=self.icon_str % self.node_type,
has_dependent=self.has_dependent_type(rset['rows'][0])
)
return make_json_response(
@@ -359,7 +369,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
scid,
row['name'],
icon=self.icon_str % self.node_type,
description=row['description']
description=row['description'],
has_dependent=self.has_dependent_type(row)
))
return make_json_response(
@@ -536,7 +547,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
enum_list = []
for row in rset['rows']:
properties_list.append(row['enumlabel'])
enum_list.append({'label': row['enumlabel']})
enum_list.append({'label': row['enumlabel'],
'old_label': row['enumlabel']})
# Adding both results in ouput
res['enum_list'] = ', '.join(properties_list)
@@ -1063,7 +1075,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
tid,
scid,
data['name'],
icon="icon-type"
icon="icon-type",
has_dependent=self.has_dependent_type(data)
)
)
except Exception as e:
@@ -1086,7 +1099,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
request.data
)
try:
SQL, name = self.get_sql(gid, sid, data, scid, tid)
SQL, name, has_dependent = self.get_sql(gid, sid, data, scid, tid)
# Most probably this is due to error
if not isinstance(SQL, str):
return SQL
@@ -1114,6 +1127,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
scid,
name,
icon=self.icon_str % self.node_type,
has_dependent=has_dependent,
**other_node_info
)
)
@@ -1226,11 +1240,15 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
for key, val in req.items():
if key in ['composite', 'enum', 'seclabels', 'typacl']:
data[key] = json.loads(val)
elif key in ['typreceive', 'typsend', 'typmodin', 'typmodout',
'typanalyze', 'typsubscript','typstorage'] and \
val == 'null':
data[key] = json.loads(val)
else:
data[key] = val
try:
sql, _ = self.get_sql(gid, sid, data, scid, tid)
sql, _, _ = self.get_sql(gid, sid, data, scid, tid)
# Most probably this is due to error
if not isinstance(sql, str):
return sql
@@ -1330,7 +1348,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
self._CREATE_SQL]),
data=data, conn=self.conn, is_sql=is_sql)
return SQL, data['name']
return SQL, data['name'], False
def get_sql(self, gid, sid, data, scid, tid=None, is_sql=False):
"""
@@ -1339,6 +1357,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
if tid is None:
return self._get_new_sql(data, is_sql)
data = self._convert_for_sql(data)
for key in ['added', 'changed', 'deleted']:
if key in data.get('typacl', []):
data['typacl'][key] = parse_priv_to_db(
@@ -1411,7 +1431,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
data=data, o_data=old_data, conn=self.conn
)
return SQL, old_data['name']
return (SQL, data['name'] if 'name' in data else old_data['name'],
self.has_dependent_type(old_data))
@check_precondition
def sql(self, gid, sid, did, scid, tid, **kwargs):
@@ -1478,7 +1499,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
if data[k] == '-':
data[k] = None
SQL, _ = self.get_sql(gid, sid, data, scid, tid=None, is_sql=True)
SQL, _, _ = self.get_sql(gid, sid, data, scid, tid=None, is_sql=True)
# Most probably this is due to error
if not isinstance(SQL, str):
return SQL
@@ -1588,8 +1609,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
if data:
if target_schema:
data['schema'] = target_schema
sql, _ = self.get_sql(gid=gid, sid=sid, scid=scid, data=data,
tid=oid)
sql, _, _ = 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,
@@ -42,6 +42,9 @@ define('pgadmin.node.type', [
hasSQL: true,
hasDepends: true,
width: pgBrowser.stdW.md + 'px',
refreshParent: function(node) {
return node?._metadata?.data?.has_dependent;
},
Init: function() {
/* Avoid multiple registration of menus */
if (this.initialized)
@@ -192,7 +192,6 @@ function isVisible(state, type) {
}
class EnumerationSchema extends BaseUISchema {
constructor() {
super({
oid: undefined,
@@ -201,18 +200,14 @@ class EnumerationSchema extends BaseUISchema {
}
get idAttribute() {
return 'oid';
return 'old_label';
}
get baseFields() {
let obj = this;
return [
{
id: 'label', label: gettext('Label'),
type: 'text', cell: 'text', minWidth: 620,
editable: (state) => {
return _.isUndefined(obj.isNew) ? true : obj.isNew(state);
}
}
];
}
@@ -395,6 +390,15 @@ class RangeSchema extends BaseUISchema {
}
};
},
}, {
id: 'rngmultirangetype', label: gettext('Multirange type name'),
cell: 'string', group: gettext('Range Type'),
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
min_version: 140000,
}
];
}
@@ -562,9 +566,6 @@ class ExternalSchema extends BaseUISchema {
group: gettext('Optional-1'),
mode: ['properties', 'create', 'edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typsend', label: gettext('Send function'),
@@ -586,9 +587,6 @@ class ExternalSchema extends BaseUISchema {
},
mode: ['properties', 'create', 'edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typmodin', label: gettext('Typmod in function'),
@@ -623,9 +621,6 @@ class ExternalSchema extends BaseUISchema {
},
mode: ['properties', 'create', 'edit'], group: gettext('Optional-1'),
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typmodout', label: gettext('Typmod out function'),
@@ -661,9 +656,24 @@ class ExternalSchema extends BaseUISchema {
},
mode: ['properties', 'create', 'edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},{
id: 'typanalyze', label: gettext('Analyze function'),
group: gettext('Optional-1'),
type: (state) => {
return obj.getFunctionType(state);
},
mode: ['properties', 'create','edit'],
disabled: () => obj.inCatalog(),
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typsubscript', label: gettext('Subscript function'),
group: gettext('Optional-1'), min_version: 140000,
type: (state) => {
return obj.getFunctionType(state);
},
mode: ['properties', 'create','edit'],
disabled: () => obj.inCatalog(),
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typlen', label: gettext('Internal length'),
cell: 'integer', group: gettext('Optional-1'),
@@ -672,14 +682,6 @@ class ExternalSchema extends BaseUISchema {
readonly: function (state) {
return !obj.isNew(state);
},
},{
id: 'variable', label: gettext('Variable?'), cell: 'switch',
group: gettext('Optional-1'), type: 'switch',
mode: ['create','edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
},{
id: 'typdefault', label: gettext('Default?'),
cell: 'string', group: gettext('Optional-1'),
@@ -688,18 +690,6 @@ class ExternalSchema extends BaseUISchema {
readonly: function (state) {
return !obj.isNew(state);
},
},{
id: 'typanalyze', label: gettext('Analyze function'),
group: gettext('Optional-1'),
type: (state) => {
return obj.getFunctionType(state);
},
mode: ['properties', 'create','edit'],
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: true, placeholder: '', width: '100%' },
},{
id: 'typcategory', label: gettext('Category type'),
cell: 'string',
@@ -792,9 +782,6 @@ class ExternalSchema extends BaseUISchema {
type: 'select', mode: ['properties', 'create', 'edit'],
group: gettext('Optional-2'), cell: 'string',
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: true, placeholder: '', width: '100%' },
options: obj.fieldOptions.typStorageOptions,
},{
@@ -1258,14 +1245,13 @@ export default class TypeSchema extends BaseUISchema {
},
{
id: 'typtype', label: gettext('Type'),
mode: ['create','edit'], group: gettext('Definition'),
type: 'select',
mode: ['create','edit', 'properties'], group: gettext('Definition'),
disabled: () => obj.inCatalog(),
readonly: function (state) {
return !obj.isNew(state);
},
controlProps: { allowClear: false },
options: function() {
type: (state)=>{
let typetype = [
{label: gettext('Composite'), value: 'c'},
{label: gettext('Enumeration'), value: 'e'},
@@ -1273,6 +1259,13 @@ export default class TypeSchema extends BaseUISchema {
{label: gettext('Range'), value: 'r'},
{label: gettext('Shell'), value: 'p'},
];
if (!obj.isNew(state)) {
typetype.push(
{label: gettext('Multirange'), value: 'm'}
);
}
if (obj.fieldOptions.server_info.server_type === 'ppas' &&
obj.fieldOptions.server_info.version >= 90500){
typetype.push(
@@ -1280,7 +1273,12 @@ export default class TypeSchema extends BaseUISchema {
{label: gettext('Varying Array'), value: 'V'}
);
}
return typetype;
return {
type: 'select',
options: typetype,
optionsReloadBasis: state.typtype,
};
},
},
{
@@ -1305,6 +1303,7 @@ export default class TypeSchema extends BaseUISchema {
schema: new EnumerationSchema(),
type: 'collection',
group: gettext('Definition'), mode: ['edit', 'create'],
uniqueCol: ['label'],
canAddRow: function(state) {
return !obj.isInvalidColumnAdded(state);
},
@@ -1389,6 +1388,12 @@ export default class TypeSchema extends BaseUISchema {
disabled: () => obj.inCatalog(),
visible: (state) => isVisible(state, 'r'),
},
{
id: 'rngmultirangetype', label: gettext('Multirange type name'), cell: 'string',
type: 'text', mode: ['properties'], group: gettext('Definition'),
disabled: () => obj.inCatalog(),
visible: (state) => isVisible(state, 'r'),
},
{
id: 'typinput', label: gettext('Input function'), cell: 'string',
type: 'text', mode: ['properties'], group: gettext('Definition'),
@@ -0,0 +1,45 @@
{# The SQL given below will fetch composite type#}
{% if typtype == 'c' %}
SELECT attnum, attname, pg_catalog.format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
(SELECT COUNT(1) from pg_catalog.pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup,
collname, nspc.nspname as collnspname, att.attrelid,
pg_catalog.format_type(t.oid, att.atttypmod) AS fulltype,
CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END as elemoid
FROM pg_catalog.pg_attribute att
JOIN pg_catalog.pg_type t ON t.oid=atttypid
JOIN pg_catalog.pg_namespace nsp ON t.typnamespace=nsp.oid
LEFT OUTER JOIN pg_catalog.pg_type b ON t.typelem=b.oid
LEFT OUTER JOIN pg_catalog.pg_collation c ON att.attcollation=c.oid
LEFT OUTER JOIN pg_catalog.pg_namespace nspc ON c.collnamespace=nspc.oid
WHERE att.attrelid = {{typrelid}}::oid
ORDER by attnum;
{% endif %}
{# The SQL given below will fetch enum type#}
{% if typtype == 'e' %}
SELECT enumlabel
FROM pg_catalog.pg_enum
WHERE enumtypid={{tid}}::oid
ORDER by enumsortorder
{% endif %}
{# The SQL given below will fetch range type#}
{% if typtype == 'r' %}
SELECT rngsubtype, st.typname,
rngcollation, mt.typname as rngmultirangetype,
CASE WHEN n.nspname IS NOT NULL THEN pg_catalog.concat(pg_catalog.quote_ident(n.nspname), '.', pg_catalog.quote_ident(col.collname)) ELSE col.collname END AS collname,
rngsubopc, opc.opcname,
rngcanonical, rngsubdiff as rngsubdiff_proc,
CASE WHEN length(ns.nspname::text) > 0 AND length(pgpr.proname::text) > 0 THEN
pg_catalog.concat(quote_ident(ns.nspname), '.', pg_catalog.quote_ident(pgpr.proname))
ELSE '' END AS rngsubdiff
FROM pg_catalog.pg_range
LEFT JOIN pg_catalog.pg_type st ON st.oid=rngsubtype
LEFT JOIN pg_catalog.pg_type mt ON mt.oid=rngmultitypid
LEFT JOIN pg_catalog.pg_collation col ON col.oid=rngcollation
LEFT JOIN pg_catalog.pg_namespace n ON col.collnamespace=n.oid
LEFT JOIN pg_catalog.pg_opclass opc ON opc.oid=rngsubopc
LEFT JOIN pg_catalog.pg_proc pgpr ON pgpr.oid = rngsubdiff
LEFT JOIN pg_catalog.pg_namespace ns ON ns.oid=pgpr.pronamespace
WHERE rngtypid={{tid}}::oid;
{% endif %}
@@ -0,0 +1,86 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
{## If user selected shell type then just create type template ##}
{% if data and data.typtype == 'p' %}
CREATE TYPE {{ conn|qtIdent(data.schema, data.name) }};
{% endif %}
{### Composite Type ###}
{% if data and data.typtype == 'c' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
({{"\n\t"}}{% if data.composite %}{% for d in data.composite %}{% if loop.index != 1 %},{{"\n\t"}}{% endif %}{{ conn|qtIdent(d.member_name) }} {% if is_sql %}{{ d.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, d.cltype, d.tlength, d.precision, d.hasSqrBracket) }}{% endif %}{% if d.collation %} COLLATE {{d.collation}}{% endif %}{% endfor %}{% endif %}{{"\n"}});
{% endif %}
{### Enum Type ###}
{% if data and data.typtype == 'e' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS ENUM
({% for e in data.enum %}{% if loop.index != 1 %}, {% endif %}{{ e.label|qtLiteral(conn) }}{% endfor %});
{% endif %}
{### Range Type ###}
{% if data and data.typtype == 'r' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS RANGE
(
{% if data.typname %}SUBTYPE={{ conn|qtTypeIdent(data.typname) }}{% endif %}{% if data.collname %},
COLLATION = {{ data.collname }}{% endif %}{% if data.opcname %},
SUBTYPE_OPCLASS = {{ data.opcname }}{% endif %}{% if data.rngcanonical %},
CANONICAL = {{ data.rngcanonical }}{% endif %}{% if data.rngsubdiff %},
SUBTYPE_DIFF = {{ data.rngsubdiff }}{% endif %}{% if data.rngmultirangetype %},
MULTIRANGE_TYPE_NAME = {{ data.rngmultirangetype }}{% endif %}
);
{% endif %}
{### External Type ###}
{% if data and data.typtype == 'b' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
(
{% if data.typinput %}INPUT = {{data.typinput}}{% endif %}{% if data.typoutput %},
OUTPUT = {{ data.typoutput }}{% endif %}{% if data.typreceive %},
RECEIVE = {{data.typreceive}}{% endif %}{% if data.typsend %},
SEND = {{data.typsend}}{% endif %}{% if data.typmodin %},
TYPMOD_IN = {{data.typmodin}}{% endif %}{% if data.typmodout %},
TYPMOD_OUT = {{data.typmodout}}{% endif %}{% if data.typanalyze %},
ANALYZE = {{data.typanalyze}}{% endif %}{% if data.typsubscript %},
SUBSCRIPT = {{data.typsubscript}}{% endif %}{% if data.typlen %},
INTERNALLENGTH = {{data.typlen}}{% endif %}{% if data.typbyval %},
PASSEDBYVALUE{% endif %}{% if data.typalign %},
ALIGNMENT = {{data.typalign}}{% endif %}{% if data.typstorage %},
STORAGE = {{data.typstorage}}{% endif %}{% if data.typcategory %},
CATEGORY = {{data.typcategory|qtLiteral(conn)}}{% endif %}{% if data.typispreferred %},
PREFERRED = {{data.typispreferred}}{% endif %}{% if data.typdefault %},
DEFAULT = {{data.typdefault|qtLiteral(conn)}}{% endif %}{% if data.element %},
ELEMENT = {{data.element}}{% endif %}{% if data.typdelim %},
DELIMITER = {{data.typdelim|qtLiteral(conn)}}{% endif %}{% if data.is_collatable %},
COLLATABLE = {{data.is_collatable}}{% endif %}
);
{% endif %}
{### Type Owner ###}
{% if data and data.typeowner %}
ALTER TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
OWNER TO {{ conn|qtIdent(data.typeowner) }};
{% endif %}
{### Type Comments ###}
{% if data and data.description %}
COMMENT ON TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
IS {{data.description|qtLiteral(conn)}};
{% endif %}
{### ACL ###}
{% if data.typacl %}
{% for priv in data.typacl %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{### Security Lables ###}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.provider and r.label %}
{{ SECLABEL.SET(conn, 'TYPE', data.name, r.provider, r.label, data.schema) }}
{% endif %}
{% endfor %}
{% endif %}
@@ -0,0 +1,19 @@
SELECT t.oid, t.typname AS name, des.description, ra.rngmultitypid as rngmultirangetype
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_catalog.pg_range ra ON ra.rngtypid=t.oid
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
{% if tid %}
AND t.oid = {{tid}}::oid
{% endif %}
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
{% if schema_diff %}
AND CASE WHEN (SELECT COUNT(*) FROM pg_catalog.pg_depend
WHERE objid = t.oid AND deptype = 'e') > 0 THEN FALSE ELSE TRUE END
{% endif %}
ORDER BY t.typname;
@@ -0,0 +1,45 @@
SELECT t.oid, t.typname AS name,
(CASE WHEN CAST(coalesce(t.typcollation, '0') AS integer) = 100 THEN true ElSE false END) AS is_collatable,
t.typacl AS type_acl,
t.typnamespace, t.typowner, t.typlen, t.typbyval, t.typtype,
t.typcategory, t.typispreferred, t.typisdefined, t.typdelim,
t.typrelid, t.typelem, t.typarray, t.typalign, t.typstorage,
t.typnotnull, t.typbasetype, t.typtypmod, t.typndims,
t.typcollation, t.typdefaultbin, t.typdefault,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typinput::oid) AS typinput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typoutput::oid) AS typoutput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typreceive::oid) AS typreceive,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typsend::oid) AS typsend,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodin::oid) AS typmodin,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodout::oid) AS typmodout,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typanalyze::oid) AS typanalyze,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typsubscript::oid) AS typsubscript,
pg_catalog.format_type(t.oid, null) AS alias,
pg_catalog.pg_get_userbyid(t.typowner) as typeowner, e.typname as element,
description, ct.oid AS taboid,
nsp.nspname AS schema,
--MinimumVersion 9.1 START
(SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabel sl1 WHERE sl1.objoid=t.oid) AS seclabels,
-- END
(CASE WHEN (t.oid <= {{ datlastsysoid}}::oid OR ct.oid != 0) THEN true ElSE false END) AS is_sys_type
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
{% if tid %}
AND t.oid = {{tid}}::oid
{% endif %}
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
ORDER BY t.typname;
@@ -0,0 +1,183 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
{#======================================#}
{# Below will change object owner #}
{% if data.typeowner and data.typeowner != o_data.typeowner %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
OWNER TO {{ conn|qtIdent(data.typeowner) }};
{% endif %}
{#======================================#}
{# Below will change objects comment #}
{% if data.description is defined and data.description != o_data.description %}
COMMENT ON TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
IS {{ data.description|qtLiteral(conn) }};
{% endif %}
{#======================================#}
{### The sql given below will update composite type ###}
{% if data.composite and data.composite|length > 0 %}
{% set composite = data.composite %}
{% if 'deleted' in composite and composite.deleted|length > 0 %}
{% for r in composite.deleted %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
DROP ATTRIBUTE {{conn|qtIdent(r.member_name)}};
{% endfor %}
{% endif %}
{% if 'added' in composite and composite.added|length > 0 %}
{% for r in composite.added %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD ATTRIBUTE {{conn|qtIdent(r.member_name)}} {{ GET_TYPE.CREATE_TYPE_SQL(conn, r.cltype, r.tlength, r.precision, r.hasSqrBracket) }}{% if r.collation %}
COLLATE {{r.collation}}{% endif %};
{% endfor %}
{% endif %}
{% if 'changed' in composite and composite.changed|length > 0 %}
{% for r in composite.changed %}
{% for o in o_data.composite %}
{##### Variables for the loop #####}
{% set member_name = o.member_name %}
{% set cltype = o.cltype %}
{% set tlength = o.tlength %}
{% set precision = o.precision %}
{% set hasSqrBracket = o.hasSqrBracket %}
{##### If member name changed #####}
{% if o.attnum == r.attnum %}
{% if r.member_name and o.member_name != r.member_name %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME ATTRIBUTE {{o.member_name}} TO {{r.member_name}};
{% set member_name = r.member_name %}
{% endif %}
{##### If type changed #####}
{% if r.cltype and cltype != r.cltype %}
{% set cltype = r.cltype %}
{% set hasSqrBracket = r.hasSqrBracket %}
{##### If length is not allowed on type #####}
{% if not r.is_tlength %}
{% set tlength = 0 %}
{% set precision = 0 %}
{% endif %}
{% endif %}
{##### If length changed #####}
{% if r.tlength and tlength != r.tlength %}
{% set tlength = r.tlength %}
{% endif %}
{##### If precision changed #####}
{% if tlength and r.precision and precision != r.precision %}
{% set precision = r.precision %}
{% endif %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ALTER ATTRIBUTE {{conn|qtIdent(member_name)}} SET DATA TYPE {{ GET_TYPE.CREATE_TYPE_SQL(conn, cltype, tlength, precision, hasSqrBracket) }}{% if r.collation %}
COLLATE {{r.collation}}{% endif %};
{% endif%}
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{### The sql given below will update enum type ###}
{% if data.enum and data.enum|length > 0 %}
{% set enum = data.enum %}
{% set o_enum_len = o_data.enum|length %}
{# We need actual list index from length #}
{% set o_enum_len = o_enum_len - 1 %}
{% if 'added' in enum and enum.added|length > 0 %}
{% for r in enum.added %}
{% set c_idx = loop.index %}
{% if c_idx == 1 %}
{# if first new element then add it after old data enum list#}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD VALUE {{r.label|qtLiteral(conn)}} {% if o_enum_len > 0 %}AFTER {{o_data.enum[o_enum_len].label|qtLiteral(conn) }}{% endif %};
{% else %}
{# if first new element then add it after new data enum list#}
{% set p_idx = loop.index - 2 %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD VALUE {{r.label|qtLiteral(conn)}} AFTER {{enum.added[p_idx].label|qtLiteral(conn)}};
{% endif %}
{% endfor %}
{% endif %}
{% if 'changed' in enum and enum.changed|length > 0 %}
{% for r in enum.changed %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME VALUE {{r.old_label|qtLiteral(conn)}} TO {{r.label|qtLiteral(conn)}};
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{### The sql given below will update External type ###}
{% if (data.typreceive is defined and data.typreceive != o_data.typreceive) or (data.typsend is defined and data.typsend != o_data.typsend) or (data.typmodin is defined and data.typmodin != o_data.typmodin) or (data.typmodout is defined and data.typmodout != o_data.typmodout) or (data.typanalyze is defined and data.typanalyze != o_data.typanalyze) or (data.typsubscript is defined and data.typsubscript != o_data.typsubscript) or (data.typstorage is defined and data.typstorage != o_data.typstorage)%}
{% set ns = namespace(add_comma=false) %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }} SET (
{% if data.typreceive is defined %}RECEIVE = {{data.typreceive}}{% set ns.add_comma = true%}{% endif %}{% if data.typsend is defined %}{% if ns.add_comma %},
{% endif %}SEND = {{data.typsend}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodin is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_IN = {{data.typmodin}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodout is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_OUT = {{data.typmodout}}{% set ns.add_comma = true%}{% endif %}{% if data.typanalyze is defined %}{% if ns.add_comma %},
{% endif %}ANALYZE = {{data.typanalyze}}{% set ns.add_comma = true%}{% endif %}{% if data.typsubscript is defined %}{% if ns.add_comma %},
{% endif %}SUBSCRIPT = {{data.typsubscript}}{% set ns.add_comma = true%}{% endif %}{% if data.typstorage is defined %}{% if ns.add_comma %},
{% endif %}STORAGE = {{data.typstorage}}{% endif %}
);
{% endif %}
{#======================================#}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.UNSET(conn, 'TYPE', o_data.name, r.provider, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{# Change the privileges #}
{% if data.typacl and data.typacl|length > 0 %}
{% if 'deleted' in data.typacl %}
{% for priv in data.typacl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.typacl %}
{% for priv in data.typacl.changed %}
{% if priv.grantee != priv.old_grantee %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.old_grantee, o_data.name, o_data.schema) }}
{% else %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
{% endif %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in data.typacl %}
{% for priv in data.typacl.added %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{# Below will change object name #}
{% if data.name and data.name != o_data.name %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{#======================================#}
{# Below will change the schema for object #}
{# with extra if condition we will also make sure that object has correct name #}
{% if data.schema and data.schema != o_data.schema %}
ALTER TYPE {% if data.name and data.name != o_data.name %}{{ conn|qtIdent(o_data.schema, data.name) }}
{% else %}{{ conn|qtIdent(o_data.schema, o_data.name) }}
{% endif %}
SET SCHEMA {{ conn|qtIdent(data.schema) }};
{% endif %}
@@ -1,6 +1,6 @@
SELECT COUNT(*)
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
{% if not showsysobj %}
AND ct.oid is NULL
@@ -1,7 +1,7 @@
{### Input/Output/Send/Receive/Analyze function list also append into TypModeIN/TypModOUT ###}
{% if extfunc %}
SELECT proname, nspname,
CASE WHEN (length(nspname::text) > 0 AND nspname != 'public') and length(proname::text) > 0 THEN
CASE WHEN length(nspname::text) > 0 and length(proname::text) > 0 THEN
pg_catalog.concat(pg_catalog.quote_ident(nspname), '.', pg_catalog.quote_ident(proname))
WHEN length(proname::text) > 0 THEN
pg_catalog.quote_ident(proname)
@@ -1,7 +1,26 @@
SELECT t.oid, t.typname AS name,
(CASE WHEN CAST(coalesce(t.typcollation, '0') AS integer) = 100 THEN true ElSE false END) AS is_collatable,
t.typacl AS type_acl,
t.*, pg_catalog.format_type(t.oid, null) AS alias,
t.typnamespace, t.typowner, t.typlen, t.typbyval, t.typtype,
t.typcategory, t.typispreferred, t.typisdefined, t.typdelim,
t.typrelid, t.typelem, t.typarray, t.typalign, t.typstorage,
t.typnotnull, t.typbasetype, t.typtypmod, t.typndims,
t.typcollation, t.typdefaultbin, t.typdefault,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typinput::oid) AS typinput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typoutput::oid) AS typoutput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typreceive::oid) AS typreceive,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typsend::oid) AS typsend,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodin::oid) AS typmodin,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodout::oid) AS typmodout,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typanalyze::oid) AS typanalyze,
pg_catalog.format_type(t.oid, null) AS alias,
pg_catalog.pg_get_userbyid(t.typowner) as typeowner, e.typname as element,
description, ct.oid AS taboid,
nsp.nspname AS schema,
@@ -97,6 +97,27 @@ ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
{% endfor %}
{% endif %}
{% if 'changed' in enum and enum.changed|length > 0 %}
{% for r in enum.changed %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME VALUE {{r.old_label|qtLiteral(conn)}} TO {{r.label|qtLiteral(conn)}};
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{### The sql given below will update External type ###}
{% if (data.typreceive is defined and data.typreceive != o_data.typreceive) or (data.typsend is defined and data.typsend != o_data.typsend) or (data.typmodin is defined and data.typmodin != o_data.typmodin) or (data.typmodout is defined and data.typmodout != o_data.typmodout) or (data.typanalyze is defined and data.typanalyze != o_data.typanalyze) or (data.typstorage is defined and data.typstorage != o_data.typstorage)%}
{% set ns = namespace(add_comma=false) %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }} SET (
{% if data.typreceive is defined %}RECEIVE = {{data.typreceive}}{% set ns.add_comma = true%}{% endif %}{% if data.typsend is defined %}{% if ns.add_comma %},
{% endif %}SEND = {{data.typsend}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodin is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_IN = {{data.typmodin}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodout is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_OUT = {{data.typmodout}}{% set ns.add_comma = true%}{% endif %}{% if data.typanalyze is defined %}{% if ns.add_comma %},
{% endif %}ANALYZE = {{data.typanalyze}}{% set ns.add_comma = true%}{% endif %}{% if data.typstorage is defined %}{% if ns.add_comma %},
{% endif %}STORAGE = {{data.typstorage}}{% endif %}
);
{% endif %}
{#======================================#}
{# The SQL generated below will change Security Label #}
@@ -0,0 +1,64 @@
{# The SQL given below will fetch composite type#}
{% if typtype == 'c' %}
SELECT attnum, attname, pg_catalog.format_type(t.oid,NULL) AS typname, attndims, atttypmod, nsp.nspname,
(SELECT COUNT(1) from pg_catalog.pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup,
collname, nspc.nspname as collnspname, att.attrelid,
pg_catalog.format_type(t.oid, att.atttypmod) AS fulltype,
CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END as elemoid
FROM pg_catalog.pg_attribute att
JOIN pg_catalog.pg_type t ON t.oid=atttypid
JOIN pg_catalog.pg_namespace nsp ON t.typnamespace=nsp.oid
LEFT OUTER JOIN pg_catalog.pg_type b ON t.typelem=b.oid
LEFT OUTER JOIN pg_catalog.pg_collation c ON att.attcollation=c.oid
LEFT OUTER JOIN pg_catalog.pg_namespace nspc ON c.collnamespace=nspc.oid
WHERE att.attrelid = {{typrelid}}::oid
ORDER by attnum;
{% endif %}
{# The SQL given below will fetch enum type#}
{% if typtype == 'e' %}
SELECT enumlabel
FROM pg_catalog.pg_enum
WHERE enumtypid={{tid}}::oid
ORDER by enumsortorder
{% endif %}
{# The SQL given below will fetch range type#}
{% if typtype == 'r' %}
SELECT rngsubtype, st.typname,
rngcollation, mt.typname as rngmultirangetype,
CASE WHEN n.nspname IS NOT NULL THEN pg_catalog.concat(pg_catalog.quote_ident(n.nspname), '.', pg_catalog.quote_ident(col.collname)) ELSE col.collname END AS collname,
rngsubopc, opc.opcname,
rngcanonical, rngsubdiff as rngsubdiff_proc,
CASE WHEN length(ns.nspname::text) > 0 AND length(pgpr.proname::text) > 0 THEN
pg_catalog.concat(quote_ident(ns.nspname), '.', pg_catalog.quote_ident(pgpr.proname))
ELSE '' END AS rngsubdiff
FROM pg_catalog.pg_range
LEFT JOIN pg_catalog.pg_type st ON st.oid=rngsubtype
LEFT JOIN pg_catalog.pg_type mt ON mt.oid=rngmultitypid
LEFT JOIN pg_catalog.pg_collation col ON col.oid=rngcollation
LEFT JOIN pg_catalog.pg_namespace n ON col.collnamespace=n.oid
LEFT JOIN pg_catalog.pg_opclass opc ON opc.oid=rngsubopc
LEFT JOIN pg_catalog.pg_proc pgpr ON pgpr.oid = rngsubdiff
LEFT JOIN pg_catalog.pg_namespace ns ON ns.oid=pgpr.pronamespace
WHERE rngtypid={{tid}}::oid;
{% endif %}
{# The SQL given below will fetch enum type#}
{% if typtype == 'N' or typtype == 'V' %}
SELECT t.typname AS typname,
CASE WHEN t.typelem > 0 THEN t.typelem ELSE t.oid END AS elemoid,
t.typtypmod,
t.typtype,
t.typndims,
pg_catalog.format_type(e.oid,NULL) AS type,
pg_catalog.format_type(e.oid, t.typtypmod) AS fulltype,
nsp.nspname as typnspname,
e.typname as type,
(SELECT COUNT(1) FROM pg_catalog.pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup,
CASE WHEN t.typcollation != 0 THEN TRUE ELSE FALSE END AS is_collatable
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON typnamespace=nsp.oid
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
WHERE t.oid={{tid}}::oid;
{% endif %}
@@ -0,0 +1,96 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
{## If user selected shell type then just create type template ##}
{% if data and data.typtype == 'p' %}
CREATE TYPE {{ conn|qtIdent(data.schema, data.name) }};
{% endif %}
{### Composite Type ###}
{% if data and data.typtype == 'c' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS
({{"\n\t"}}{% if data.composite %}{% for d in data.composite %}{% if loop.index != 1 %},{{"\n\t"}}{% endif %}{{ conn|qtIdent(d.member_name) }} {% if is_sql %}{{ d.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, d.cltype, d.tlength, d.precision, d.hasSqrBracket) }}{% endif %}{% if d.collation %} COLLATE {{d.collation}}{% endif %}{% endfor %}{% endif %}{{"\n"}});
{% endif %}
{### Enum Type ###}
{% if data and data.typtype == 'e' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS ENUM
({% for e in data.enum %}{% if loop.index != 1 %}, {% endif %}{{ e.label|qtLiteral(conn) }}{% endfor %});
{% endif %}
{### Range Type ###}
{% if data and data.typtype == 'r' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS RANGE
(
{% if data.typname %}SUBTYPE={{ conn|qtTypeIdent(data.typname) }}{% endif %}{% if data.collname %},
COLLATION = {{ data.collname }}{% endif %}{% if data.opcname %},
SUBTYPE_OPCLASS = {{ data.opcname }}{% endif %}{% if data.rngcanonical %},
CANONICAL = {{ data.rngcanonical }}{% endif %}{% if data.rngsubdiff %},
SUBTYPE_DIFF = {{ data.rngsubdiff }}{% endif %}{% if data.rngmultirangetype %},
MULTIRANGE_TYPE_NAME = {{ data.rngmultirangetype }}{% endif %}
);
{% endif %}
{### External Type ###}
{% if data and data.typtype == 'b' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
(
{% if data.typinput %}INPUT = {{data.typinput}}{% endif %}{% if data.typoutput %},
OUTPUT = {{ data.typoutput }}{% endif %}{% if data.typreceive %},
RECEIVE = {{data.typreceive}}{% endif %}{% if data.typsend %},
SEND = {{data.typsend}}{% endif %}{% if data.typmodin %},
TYPMOD_IN = {{data.typmodin}}{% endif %}{% if data.typmodout %},
TYPMOD_OUT = {{data.typmodout}}{% endif %}{% if data.typanalyze %},
ANALYZE = {{data.typanalyze}}{% endif %}{% if data.typsubscript %},
SUBSCRIPT = {{data.typsubscript}}{% endif %}{% if data.typlen %},
INTERNALLENGTH = {{data.typlen}}{% endif %}{% if data.typbyval %},
PASSEDBYVALUE{% endif %}{% if data.typalign %},
ALIGNMENT = {{data.typalign}}{% endif %}{% if data.typstorage %},
STORAGE = {{data.typstorage}}{% endif %}{% if data.typcategory %},
CATEGORY = {{data.typcategory|qtLiteral(conn)}}{% endif %}{% if data.typispreferred %},
PREFERRED = {{data.typispreferred}}{% endif %}{% if data.typdefault %},
DEFAULT = {{data.typdefault|qtLiteral(conn)}}{% endif %}{% if data.element %},
ELEMENT = {{data.element}}{% endif %}{% if data.typdelim %},
DELIMITER = {{data.typdelim|qtLiteral(conn)}}{% endif %}{% if data.is_collatable %},
COLLATABLE = {{data.is_collatable}}{% endif %}
);
{% endif %}
{### Nested-table Type ###}
{% if data and data.typtype == 'N' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS TABLE OF
{% if is_sql %}{{ data.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.tlength, data.precision, data.hasSqrBracket) }}{% endif %};
{% endif %}
{### VARRAY Type ###}
{% if data and data.typtype == 'V' %}
CREATE TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} AS VARRAY({{data.maxsize}}) OF
{% if is_sql %}{{ data.fulltype }}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.tlength, data.precision, data.hasSqrBracket) }}{% endif %};
{% endif %}
{### Type Owner ###}
{% if data and data.typeowner %}
ALTER TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
OWNER TO {{ conn|qtIdent(data.typeowner) }};
{% endif %}
{### Type Comments ###}
{% if data and data.description %}
COMMENT ON TYPE {% if data.schema %}{{ conn|qtIdent(data.schema, data.name) }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %}
IS {{data.description|qtLiteral(conn)}};
{% endif %}
{### ACL ###}
{% if data.typacl %}
{% for priv in data.typacl %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{### Security Lables ###}
{% if data.seclabels %}
{% for r in data.seclabels %}
{% if r.provider and r.label %}
{{ SECLABEL.SET(conn, 'TYPE', data.name, r.provider, r.label, data.schema) }}
{% endif %}
{% endfor %}
{% endif %}
@@ -0,0 +1,19 @@
SELECT t.oid, t.typname AS name, des.description, ra.rngmultitypid as rngmultirangetype
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_catalog.pg_range ra ON ra.rngtypid=t.oid
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
{% if tid %}
AND t.oid = {{tid}}::oid
{% endif %}
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
{% if schema_diff %}
AND CASE WHEN (SELECT COUNT(*) FROM pg_catalog.pg_depend
WHERE objid = t.oid AND deptype = 'e') > 0 THEN FALSE ELSE TRUE END
{% endif %}
ORDER BY t.typname;
@@ -0,0 +1,45 @@
SELECT t.oid, t.typname AS name,
(CASE WHEN CAST(coalesce(t.typcollation, '0') AS integer) = 100 THEN true ElSE false END) AS is_collatable,
t.typacl AS type_acl,
t.typnamespace, t.typowner, t.typlen, t.typbyval, t.typtype,
t.typcategory, t.typispreferred, t.typisdefined, t.typdelim,
t.typrelid, t.typelem, t.typarray, t.typalign, t.typstorage,
t.typnotnull, t.typbasetype, t.typtypmod, t.typndims,
t.typcollation, t.typdefaultbin, t.typdefault,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typinput::oid) AS typinput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typoutput::oid) AS typoutput,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typreceive::oid) AS typreceive,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typsend::oid) AS typsend,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodin::oid) AS typmodin,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typmodout::oid) AS typmodout,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typanalyze::oid) AS typanalyze,
(SELECT pg_catalog.concat(nspname, '.', proname,'') FROM pg_proc pr JOIN pg_namespace nsp ON pr.pronamespace = nsp.oid
WHERE pr.oid = t.typsubscript::oid) AS typsubscript,
pg_catalog.format_type(t.oid, null) AS alias,
pg_catalog.pg_get_userbyid(t.typowner) as typeowner, e.typname as element,
description, ct.oid AS taboid,
nsp.nspname AS schema,
--MinimumVersion 9.1 START
(SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabel sl1 WHERE sl1.objoid=t.oid) AS seclabels,
-- END
(CASE WHEN (t.oid <= {{ datlastsysoid}}::oid OR ct.oid != 0) THEN true ElSE false END) AS is_sys_type
FROM pg_catalog.pg_type t
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
{% if tid %}
AND t.oid = {{tid}}::oid
{% endif %}
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
ORDER BY t.typname;
@@ -0,0 +1,183 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
{#======================================#}
{# Below will change object owner #}
{% if data.typeowner and data.typeowner != o_data.typeowner %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
OWNER TO {{ conn|qtIdent(data.typeowner) }};
{% endif %}
{#======================================#}
{# Below will change objects comment #}
{% if data.description is defined and data.description != o_data.description %}
COMMENT ON TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
IS {{ data.description|qtLiteral(conn) }};
{% endif %}
{#======================================#}
{### The sql given below will update composite type ###}
{% if data.composite and data.composite|length > 0 %}
{% set composite = data.composite %}
{% if 'deleted' in composite and composite.deleted|length > 0 %}
{% for r in composite.deleted %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
DROP ATTRIBUTE {{conn|qtIdent(r.member_name)}};
{% endfor %}
{% endif %}
{% if 'added' in composite and composite.added|length > 0 %}
{% for r in composite.added %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD ATTRIBUTE {{conn|qtIdent(r.member_name)}} {{ GET_TYPE.CREATE_TYPE_SQL(conn, r.cltype, r.tlength, r.precision, r.hasSqrBracket) }}{% if r.collation %}
COLLATE {{r.collation}}{% endif %};
{% endfor %}
{% endif %}
{% if 'changed' in composite and composite.changed|length > 0 %}
{% for r in composite.changed %}
{% for o in o_data.composite %}
{##### Variables for the loop #####}
{% set member_name = o.member_name %}
{% set cltype = o.cltype %}
{% set tlength = o.tlength %}
{% set precision = o.precision %}
{% set hasSqrBracket = o.hasSqrBracket %}
{##### If member name changed #####}
{% if o.attnum == r.attnum %}
{% if r.member_name and o.member_name != r.member_name %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME ATTRIBUTE {{o.member_name}} TO {{r.member_name}};
{% set member_name = r.member_name %}
{% endif %}
{##### If type changed #####}
{% if r.cltype and cltype != r.cltype %}
{% set cltype = r.cltype %}
{% set hasSqrBracket = r.hasSqrBracket %}
{##### If length is not allowed on type #####}
{% if not r.is_tlength %}
{% set tlength = 0 %}
{% set precision = 0 %}
{% endif %}
{% endif %}
{##### If length changed #####}
{% if r.tlength and tlength != r.tlength %}
{% set tlength = r.tlength %}
{% endif %}
{##### If precision changed #####}
{% if tlength and r.precision and precision != r.precision %}
{% set precision = r.precision %}
{% endif %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ALTER ATTRIBUTE {{conn|qtIdent(member_name)}} SET DATA TYPE {{ GET_TYPE.CREATE_TYPE_SQL(conn, cltype, tlength, precision, hasSqrBracket) }}{% if r.collation %}
COLLATE {{r.collation}}{% endif %};
{% endif%}
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{### The sql given below will update enum type ###}
{% if data.enum and data.enum|length > 0 %}
{% set enum = data.enum %}
{% set o_enum_len = o_data.enum|length %}
{# We need actual list index from length #}
{% set o_enum_len = o_enum_len - 1 %}
{% if 'added' in enum and enum.added|length > 0 %}
{% for r in enum.added %}
{% set c_idx = loop.index %}
{% if c_idx == 1 %}
{# if first new element then add it after old data enum list#}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD VALUE {{r.label|qtLiteral(conn)}} {% if o_enum_len > 0 %}AFTER {{o_data.enum[o_enum_len].label|qtLiteral(conn) }}{% endif %};
{% else %}
{# if first new element then add it after new data enum list#}
{% set p_idx = loop.index - 2 %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
ADD VALUE {{r.label|qtLiteral(conn)}} AFTER {{enum.added[p_idx].label|qtLiteral(conn)}};
{% endif %}
{% endfor %}
{% endif %}
{% if 'changed' in enum and enum.changed|length > 0 %}
{% for r in enum.changed %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME VALUE {{r.old_label|qtLiteral(conn)}} TO {{r.label|qtLiteral(conn)}};
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{### The sql given below will update External type ###}
{% if (data.typreceive is defined and data.typreceive != o_data.typreceive) or (data.typsend is defined and data.typsend != o_data.typsend) or (data.typmodin is defined and data.typmodin != o_data.typmodin) or (data.typmodout is defined and data.typmodout != o_data.typmodout) or (data.typanalyze is defined and data.typanalyze != o_data.typanalyze) or (data.typsubscript is defined and data.typsubscript != o_data.typsubscript) or (data.typstorage is defined and data.typstorage != o_data.typstorage)%}
{% set ns = namespace(add_comma=false) %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }} SET (
{% if data.typreceive is defined %}RECEIVE = {{data.typreceive}}{% set ns.add_comma = true%}{% endif %}{% if data.typsend is defined %}{% if ns.add_comma %},
{% endif %}SEND = {{data.typsend}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodin is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_IN = {{data.typmodin}}{% set ns.add_comma = true%}{% endif %}{% if data.typmodout is defined %}{% if ns.add_comma %},
{% endif %}TYPMOD_OUT = {{data.typmodout}}{% set ns.add_comma = true%}{% endif %}{% if data.typanalyze is defined %}{% if ns.add_comma %},
{% endif %}ANALYZE = {{data.typanalyze}}{% set ns.add_comma = true%}{% endif %}{% if data.typsubscript is defined %}{% if ns.add_comma %},
{% endif %}SUBSCRIPT = {{data.typsubscript}}{% set ns.add_comma = true%}{% endif %}{% if data.typstorage is defined %}{% if ns.add_comma %},
{% endif %}STORAGE = {{data.typstorage}}{% endif %}
);
{% endif %}
{#======================================#}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.UNSET(conn, 'TYPE', o_data.name, r.provider, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.SET(conn, 'TYPE', o_data.name, r.provider, r.label, o_data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{# Change the privileges #}
{% if data.typacl and data.typacl|length > 0 %}
{% if 'deleted' in data.typacl %}
{% for priv in data.typacl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.typacl %}
{% for priv in data.typacl.changed %}
{% if priv.grantee != priv.old_grantee %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.old_grantee, o_data.name, o_data.schema) }}
{% else %}
{{ PRIVILEGE.UNSETALL(conn, 'TYPE', priv.grantee, o_data.name, o_data.schema) }}
{% endif %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in data.typacl %}
{% for priv in data.typacl.added %}
{{ PRIVILEGE.SET(conn, 'TYPE', priv.grantee, o_data.name, priv.without_grant, priv.with_grant, o_data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{#======================================#}
{# Below will change object name #}
{% if data.name and data.name != o_data.name %}
ALTER TYPE {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{#======================================#}
{# Below will change the schema for object #}
{# with extra if condition we will also make sure that object has correct name #}
{% if data.schema and data.schema != o_data.schema %}
ALTER TYPE {% if data.name and data.name != o_data.name %}{{ conn|qtIdent(o_data.schema, data.name) }}
{% else %}{{ conn|qtIdent(o_data.schema, o_data.name) }}
{% endif %}
SET SCHEMA {{ conn|qtIdent(data.schema) }};
{% endif %}
Loaded 100 of 202 files, more files were not shown because too many files have changed in this diff. Show more