Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3416184236 | ||
|
|
6e3ee1c607 | ||
|
|
b512404c85 | ||
|
|
5bb6e9133f | ||
|
|
344c236d72 | ||
|
|
b4b2a4ff67 | ||
|
|
205a661922 | ||
|
|
eead9b77e7 | ||
|
|
47e734dbf2 | ||
|
|
ce372a73bf | ||
|
|
10c5d25735 | ||
|
|
81dcc91747 | ||
|
|
3a62fc5a2a | ||
|
|
10adb6a11b | ||
|
|
82fade7645 | ||
|
|
37dced23f0 | ||
|
|
6f857bdbcb | ||
|
|
6ba9c192ce | ||
|
|
221af6caa6 | ||
|
|
e22492ad51 | ||
|
|
2b8efc6361 | ||
|
|
73430a2062 | ||
|
|
fc411bfc49 | ||
|
|
4450145d31 | ||
|
|
cd84200135 | ||
|
|
6997d0149e | ||
|
|
5981f4bd13 | ||
|
|
5113fda7a6 | ||
|
|
7ce07f7dcf | ||
|
|
078a959e3d | ||
|
|
b4f517f7ff | ||
|
|
36dc2e9d2a | ||
|
|
858c85adbe | ||
|
|
2cd86449d0 | ||
|
|
c37fb061bd | ||
|
|
dc9cc3730b | ||
|
|
872b60de5c | ||
|
|
5d2ce142dd | ||
|
|
9666bd6c8d | ||
|
|
0b3c79865e | ||
|
|
9c903f944c | ||
|
|
541d9dfcb4 | ||
|
|
b9d3006915 | ||
|
|
68b7ddb592 | ||
|
|
4309aa3ba7 | ||
|
|
f9bbadfc6a | ||
|
|
c6f8918983 | ||
|
|
16c95d21a7 | ||
|
|
bae912fa40 | ||
|
|
ca3ec76db6 | ||
|
|
4050545f7c | ||
|
|
975bcd9fb0 | ||
|
|
3cd547f879 | ||
|
|
5736e173ea | ||
|
|
5a26cad588 | ||
|
|
3b616b2fb1 | ||
|
|
35f05e49b3 | ||
|
|
61fa8b16c9 | ||
|
|
3258851425 | ||
|
|
0f5450c6d2 | ||
|
|
07f18a1b05 | ||
|
|
02ecc82e73 | ||
|
|
0d111e0fb6 | ||
|
|
7af597eca2 | ||
|
|
64c71becc6 | ||
|
|
ffec77d50b | ||
|
|
d69b4282c8 | ||
|
|
aa973fc8ae | ||
|
|
8c91d40932 | ||
|
|
2f5fb6a996 | ||
|
|
cfc338c5f0 | ||
|
|
32403920fe | ||
|
|
e9384615dc | ||
|
|
07d965ea46 | ||
|
|
a43b70e360 | ||
|
|
095e11247d | ||
|
|
88162c683e | ||
|
|
cf3c696f7e | ||
|
|
02eaf787e9 | ||
|
|
e5c249e81c | ||
|
|
c0b868b53b | ||
|
|
39a14920e3 | ||
|
|
5cf9dea9a8 | ||
|
|
0b7eafaca0 | ||
|
|
ed8aeed818 | ||
|
|
0b91244f91 | ||
|
|
46c67a2f4e | ||
|
|
c87e925991 | ||
|
|
5fb80af90e | ||
|
|
77467209c2 | ||
|
|
cd613ded0a | ||
|
|
e8283173ba |
No files matched your search
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-container:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-docs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
check-javascript-style:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-python-package:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
check-python-style:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build-tarball:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
check-translations:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-feature-tests-epas:
|
||||
# Only run if the tests are enabled
|
||||
# TODO: Figure out a way to test for the presence of the secrets instead
|
||||
if: vars.ENABLE_EPAS_TESTS == 'true'
|
||||
|
||||
@@ -16,11 +16,11 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-feature-tests-pg:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pgver: [11, 12, 13, 14, 15]
|
||||
pgver: [12, 13, 14, 15, 16]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-javascript-tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
- name: Upgrade yarn
|
||||
run: |
|
||||
yarn set version berry
|
||||
|
||||
@@ -23,7 +23,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-python-tests-epas:
|
||||
# Only run if the tests are enabled
|
||||
# TODO: Figure out a way to test for the presence of the secrets instead
|
||||
if: vars.ENABLE_EPAS_TESTS == 'true'
|
||||
|
||||
@@ -16,12 +16,12 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-python-tests-pg:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
pgver: [11, 12, 13, 14, 15]
|
||||
pgver: [12, 13, 14, 15, 16]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -57,7 +57,9 @@ jobs:
|
||||
- name: Install platform dependencies on Windows
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
run: |
|
||||
choco install -y postgresql${{ matrix.pgver }} --params "/Password:postgres /Port:59${{ matrix.pgver }}" --ia "--prefix C:\PostgreSQL\${{ matrix.pgver }} --datadir C:\PostgreSQL\${{ matrix.pgver }}\data --install_runtimes 0 --disable-components pgAdmin,stackbuilder --enable-components server,commandlinetools"
|
||||
FOR /f "delims=" %%F IN ('python tools\get_sb_package.py "https://www.postgresql.org/applications-v2.xml" "postgresql_${{ matrix.pgver }}" "windows-x64"') DO SET INSTALLER_EXE=%%F
|
||||
ECHO Running %INSTALLER_EXE%...
|
||||
%INSTALLER_EXE% --prefix C:\PostgreSQL\${{ matrix.pgver }} --datadir C:\PostgreSQL\${{ matrix.pgver }}\data --serverport 59${{ matrix.pgver }} --superpassword postgres --install_runtimes 0 --mode unattended --unattendedmodeui none --disable-components pgAdmin,stackbuilder --enable-components server,commandlinetools"
|
||||
choco install -y mitkerberos
|
||||
|
||||
REM Ignore error 3010 (reboot required)
|
||||
|
||||
@@ -18,7 +18,7 @@ concurrency:
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
run-sonarqube-scan:
|
||||
# Only run if the project key is set
|
||||
if: vars.SONARQUBE_PROJECT_KEY != null
|
||||
|
||||
|
||||
@@ -114,20 +114,15 @@ RUN rm -rf /pgadmin4/docs/en_US/_build/html/_static/*.png
|
||||
# Create additional builders to get all of the PostgreSQL utilities
|
||||
#########################################################################
|
||||
|
||||
FROM postgres:11-alpine AS pg11-builder
|
||||
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 alpine:latest AS tool-builder
|
||||
|
||||
# Copy the PG binaries
|
||||
COPY --from=pg11-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-11/
|
||||
COPY --from=pg11-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-11/
|
||||
COPY --from=pg11-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-11/
|
||||
COPY --from=pg11-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-11/
|
||||
|
||||
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/
|
||||
@@ -148,6 +143,11 @@ COPY --from=pg15-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-15/
|
||||
COPY --from=pg15-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-15/
|
||||
COPY --from=pg15-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-15/
|
||||
|
||||
COPY --from=pg16-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-16/
|
||||
COPY --from=pg16-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-16/
|
||||
COPY --from=pg16-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-16/
|
||||
COPY --from=pg16-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-16/
|
||||
|
||||
#########################################################################
|
||||
# Assemble everything into the final container.
|
||||
#########################################################################
|
||||
@@ -159,9 +159,14 @@ COPY --from=env-builder /venv /venv
|
||||
|
||||
# Copy in the tools
|
||||
COPY --from=tool-builder /usr/local/pgsql /usr/local/
|
||||
COPY --from=pg15-builder /usr/local/lib/libpq.so.5.15 /usr/lib/
|
||||
RUN ln -s libpq.so.5.15 /usr/lib/libpq.so.5 && \
|
||||
ln -s libpq.so.5.15 /usr/lib/libpq.so
|
||||
COPY --from=pg16-builder /usr/local/lib/libpq.so.5.16 /usr/lib/
|
||||
COPY --from=pg16-builder /usr/lib/libzstd.so.1.5.5 /usr/lib/
|
||||
COPY --from=pg16-builder /usr/lib/liblz4.so.1.9.4 /usr/lib/
|
||||
|
||||
RUN ln -s libpq.so.5.16 /usr/lib/libpq.so.5 && \
|
||||
ln -s libpq.so.5.16 /usr/lib/libpq.so && \
|
||||
ln -s libzstd.so.1.5.5 /usr/lib/libzstd.so.1 && \
|
||||
ln -s liblz4.so.1.9.4 /usr/lib/liblz4.so.1
|
||||
|
||||
WORKDIR /pgadmin4
|
||||
ENV PYTHONPATH=/pgadmin4
|
||||
|
||||
@@ -26,8 +26,8 @@ CALL :CLEAN || EXIT /B 1
|
||||
CALL :CREATE_VIRTUAL_ENV || EXIT /B 1
|
||||
CALL :CREATE_PYTHON_ENV || EXIT /B 1
|
||||
CALL :CREATE_RUNTIME_ENV || EXIT /B 1
|
||||
CALL :CREATE_INSTALLER || EXIT /B 1
|
||||
CALL :GENERATE_SBOM || EXIT /B 1
|
||||
CALL :CREATE_INSTALLER || EXIT /B 1
|
||||
CALL :SIGN_INSTALLER || EXIT /B 1
|
||||
|
||||
EXIT /B %ERRORLEVEL%
|
||||
@@ -315,8 +315,8 @@ REM Main build sequence Ends
|
||||
|
||||
ECHO Staging PostgreSQL components...
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libpq.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libcrypto-1_1-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libssl-1_1-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libcrypto-*-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libssl-*-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" "%BUILDROOT%\runtime" > nul
|
||||
IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" "%BUILDROOT%\runtime" > nul
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\zlib.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
@@ -364,7 +364,7 @@ REM Main build sequence Ends
|
||||
|
||||
:GENERATE_SBOM
|
||||
ECHO Generating SBOM...
|
||||
syft "%BUILDROOT%\" -o cyclonedx-json > "%BUILDROOT%\sbom.json"
|
||||
CALL syft "%BUILDROOT%" -o cyclonedx-json > "%BUILDROOT%\sbom.json"
|
||||
|
||||
:SIGN_INSTALLER
|
||||
ECHO Attempting to sign the installer...
|
||||
|
||||
@@ -251,6 +251,16 @@ tab to provide other backup options.
|
||||
table locks at the beginning of the dump. Instead, fail if unable to lock a
|
||||
table within the specified timeout.
|
||||
|
||||
Click the *Objects* tab to continue.
|
||||
|
||||
.. image:: images/backup_object_selection.png
|
||||
:alt: Select objects in backup dialog
|
||||
:align: center
|
||||
|
||||
* Select the objects from tree to take backup of selected objects only.
|
||||
* If Schema is selected then it will take the backup of that selected schema only.
|
||||
* If any Table, View, Materialized View, Sequences, or Foreign Table is selected then it will take the backup of those selected objects.
|
||||
|
||||
When you’ve specified the details that will be incorporated into the pg_dump
|
||||
command:
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ are disabled if inapplicable.)
|
||||
a text value.
|
||||
* Use the drop-down listbox next to *Collation* to apply a collation setting to
|
||||
the column.
|
||||
* Use the drop-down listbox next to *Compression* to set the compression method
|
||||
for the column. Compression is supported only for variable-width data types,
|
||||
and is used only when the column's storage mode is main or extended. This
|
||||
option is available from v14 and above.
|
||||
|
||||
Click the *Constraints* tab to continue.
|
||||
|
||||
|
||||
@@ -53,11 +53,11 @@ The default binary paths set in the container are as follows:
|
||||
.. code-block:: bash
|
||||
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
'pg-16': '/usr/local/pgsql-16',
|
||||
'pg-15': '/usr/local/pgsql-15',
|
||||
'pg-14': '/usr/local/pgsql-14',
|
||||
'pg-13': '/usr/local/pgsql-13',
|
||||
'pg-12': '/usr/local/pgsql-12',
|
||||
'pg-11': '/usr/local/pgsql-11'
|
||||
'pg-12': '/usr/local/pgsql-12'
|
||||
}
|
||||
|
||||
this may be changed in the :ref:`preferences`.
|
||||
|
||||
@@ -19,6 +19,9 @@ Use the fields in the *General* tab to identify the database:
|
||||
|
||||
* Use the *Database* field to add a descriptive name for the database. The name
|
||||
will be displayed in the *pgAdmin* tree control.
|
||||
* Use the *OID* field to specify the object identifier to be used for the new
|
||||
database. Users can specify the value greater than 16383. This option is available
|
||||
from v15 and above.
|
||||
* Select the owner of the database from the drop-down listbox in the *Owner*
|
||||
field.
|
||||
* Store notes about the database in the *Comment* field.
|
||||
@@ -38,11 +41,22 @@ Use the *Definition* tab to set properties for the database:
|
||||
* Select a tablespace from the drop-down listbox in the *Tablespace* field. The
|
||||
selected tablespace will be the default tablespace used to contain database
|
||||
objects.
|
||||
* Select the strategy from the drop-down listbox in the *Strategy* field while
|
||||
creating a new database. This option is available from v15 and above.
|
||||
* Select the locale provider from the drop-down listbox in the *Locale Provider*
|
||||
field to set the default collation for this database. Possible values are: icu, libc.
|
||||
This option is available from v15 and above.
|
||||
* Select the collation order from the drop-down listbox in the *Collation* field.
|
||||
* Select the character classification from the drop-down listbox in the
|
||||
*Character Type* field. This affects the categorization of characters, e.g.
|
||||
lower, upper and digit. The default, or a blank field, uses the character
|
||||
classification of the template database.
|
||||
* Select the icu locale from the drop-down listbox in the *ICU Locale* to
|
||||
specifies the ICU locale ID if the ICU locale provider is used.
|
||||
This option is available from v15 and above.
|
||||
* Specify the icu rules in the *ICU Rules* field as additional collation
|
||||
rules to customize the behavior of the default collation of this database.
|
||||
This option is available from v16 and above.
|
||||
* Specify a connection limit in the *Connection Limit* field to configure the
|
||||
maximum number of connection requests. The default value (*-1*) allows
|
||||
unlimited connections to the database.
|
||||
|
||||
|
After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 94 KiB |
@@ -31,17 +31,6 @@ Use the fields in the *General* tab to identify the materialized view:
|
||||
Click the *Definition* tab to continue.
|
||||
|
||||
.. image:: images/materialized_view_definition.png
|
||||
:alt: Materialized view dialog definition tab
|
||||
:align: center
|
||||
|
||||
Use the text editor field in the *Definition* tab to provide the query that will
|
||||
populate the materialized view. Please note that updating the definition of existing
|
||||
materialized view would result in loss of Parameter(Table, Toast), Security(Privileges & Security labels),
|
||||
Indexes and other dependent objects.
|
||||
|
||||
Click the *Storage* tab to continue.
|
||||
|
||||
.. image:: images/materialized_view_storage.png
|
||||
:alt: Materialized view dialog storage tab
|
||||
:align: center
|
||||
|
||||
@@ -52,10 +41,24 @@ Use the fields in the *Storage* tab to maintain the materialized view:
|
||||
cannot be queried until you invoke REFRESH MATERIALIZED VIEW.
|
||||
* Use the drop-down listbox next to *Tablespace* to select a location for the
|
||||
materialized view.
|
||||
* Use the drop-down list box next to Access Method to specify the table access method to use to store the contents
|
||||
for the new materialized view; the method needs to be an access method of type TABLE. This field is optional.
|
||||
This option is available from v12 and above.
|
||||
* Use the *Fill Factor* field to specify a fill factor for the materialized
|
||||
view. The fill factor for a table is a percentage between 10 and 100. 100
|
||||
(complete packing) is the default.
|
||||
|
||||
Click the *Code* tab to continue.
|
||||
|
||||
.. image:: images/materialized_view_code.png
|
||||
:alt: Materialized view dialog definition tab
|
||||
:align: center
|
||||
|
||||
Use the text editor field in the *Code* tab to provide the query that will
|
||||
populate the materialized view. Please note that updating the definition of existing
|
||||
materialized view would result in loss of Parameter(Table, Toast), Security(Privileges & Security labels),
|
||||
Indexes and other dependent objects.
|
||||
|
||||
Click the *Parameter* tab to continue.
|
||||
|
||||
.. image:: images/materialized_view_parameter.png
|
||||
|
||||
@@ -12,6 +12,10 @@ installed in Server mode. You can copy these settings from *config.py* file
|
||||
and modify the values for the following parameters:
|
||||
|
||||
|
||||
.. _AzureAD: https://learn.microsoft.com/en-us/security/zero-trust/develop/configure-tokens-group-claims-app-roles
|
||||
.. _GitLab: https://docs.gitlab.com/ee/integration/openid_connect_provider.html#shared-information
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:header: "**Parameter**", "**Description**"
|
||||
:class: longtable
|
||||
@@ -39,6 +43,9 @@ and modify the values for the following parameters:
|
||||
"OAUTH2_AUTO_CREATE_USER", "Set the value to *True* if you want to automatically
|
||||
create a pgAdmin user corresponding to a successfully authenticated Oauth2 user.
|
||||
Please note that password is not stored in the pgAdmin database."
|
||||
"OAUTH2_ADDITIONAL_CLAIMS", "If a dictionary is provided, pgAdmin will check for a matching key and value on the user profile.
|
||||
In case the profile does not have any match with the provided config, the user will receive an authorization error.
|
||||
Useful for checking AzureAD_ *wids* or *groups*, GitLab_ *owner*, *maintainer* and *reporter* claims."
|
||||
|
||||
Redirect URL
|
||||
============
|
||||
|
||||
@@ -11,6 +11,8 @@ notes for it.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_7_8
|
||||
release_notes_7_7
|
||||
release_notes_7_6
|
||||
release_notes_7_5
|
||||
release_notes_7_4
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
***********
|
||||
Version 7.7
|
||||
***********
|
||||
|
||||
Release date: 2023-09-21
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.6.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 11, 12, 13, 14 and 15
|
||||
|
||||
**EDB Advanced Server**: 11, 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 15.4
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #642 <https://github.com/pgadmin-org/pgadmin4/issues/642>`_ - Added support to select/deselect objects in the Backup dialog.
|
||||
| `Issue #4805 <https://github.com/pgadmin-org/pgadmin4/issues/4805>`_ - Added all the new options of the 'WITH' clause in the subscription dialog.
|
||||
| `Issue #6378 <https://github.com/pgadmin-org/pgadmin4/issues/6378>`_ - Added USING method while creating the table.
|
||||
| `Issue #6379 <https://github.com/pgadmin-org/pgadmin4/issues/6379>`_ - Added compression method option while creating a column.
|
||||
| `Issue #6383 <https://github.com/pgadmin-org/pgadmin4/issues/6383>`_ - Added Strategy, Locale Provider, ICU Locale, ICU Rules, and OID options while creating a database.
|
||||
| `Issue #6400 <https://github.com/pgadmin-org/pgadmin4/issues/6400>`_ - Added USING method while creating the materialized view.
|
||||
| `Issue #6736 <https://github.com/pgadmin-org/pgadmin4/issues/6736>`_ - Add support for additional ID token claim checks for OAuth 2 authentication.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #2411 <https://github.com/pgadmin-org/pgadmin4/issues/2411>`_ - Added the 'data type' column in the properties tab of the Columns collection node.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #6274 <https://github.com/pgadmin-org/pgadmin4/issues/6274>`_ - Fix an issue where user is not able to change the password when SMTP is not configured.
|
||||
| `Issue #6704 <https://github.com/pgadmin-org/pgadmin4/issues/6704>`_ - Ensure user is redirected to login page after failed login.
|
||||
| `Issue #6712 <https://github.com/pgadmin-org/pgadmin4/issues/6712>`_ - Ensure that Materialized view size fields in "Statistics" should be human-readable.
|
||||
| `Issue #6730 <https://github.com/pgadmin-org/pgadmin4/issues/6730>`_ - Fix an issue where changing the password shows success but the new password is not working.
|
||||
| `Issue #6738 <https://github.com/pgadmin-org/pgadmin4/issues/6738>`_ - Fix an issue where login form doesn't appear if internal auth source is removed.
|
||||
| `Issue #6764 <https://github.com/pgadmin-org/pgadmin4/issues/6764>`_ - Fix a security related issue where an authenticated user can run remote command using validate binary path API (CVE-2023-5002).
|
||||
@@ -0,0 +1,51 @@
|
||||
***********
|
||||
Version 7.8
|
||||
***********
|
||||
|
||||
Release date: 2023-10-19
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v7.7.
|
||||
|
||||
Supported Database Servers
|
||||
**************************
|
||||
**PostgreSQL**: 12, 13, 14, 15, and 16
|
||||
|
||||
**EDB Advanced Server**: 12, 13, 14 and 15
|
||||
|
||||
Bundled PostgreSQL Utilities
|
||||
****************************
|
||||
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 16.0
|
||||
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #640 <https://github.com/pgadmin-org/pgadmin4/issues/640>`_ - Add support for foreign table's new functionality for PG 11 and above.
|
||||
| `Issue #6229 <https://github.com/pgadmin-org/pgadmin4/issues/6229>`_ - Allow setting custom username for shared servers, with default as username of server being shared.
|
||||
| `Issue #6373 <https://github.com/pgadmin-org/pgadmin4/issues/6373>`_ - Add 'GENERATED ALWAYS AS..' option while creating column constraints for Foreign Table.
|
||||
| `Issue #6797 <https://github.com/pgadmin-org/pgadmin4/issues/6797>`_ - GUI representation of the system's activity using the 'system_stats' extension.
|
||||
| `Issue #6802 <https://github.com/pgadmin-org/pgadmin4/issues/6802>`_ - Added 'load_balance_hosts' connection string parameter for PG 16 and above.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #6782 <https://github.com/pgadmin-org/pgadmin4/issues/6782>`_ - Use PG16 as the default PostgreSQL version.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #4995 <https://github.com/pgadmin-org/pgadmin4/issues/4995>`_ - Fixed an issue in ERD tool where the downloaded images have a few links cut.
|
||||
| `Issue #5749 <https://github.com/pgadmin-org/pgadmin4/issues/5749>`_ - Fixed an issue where user was not able to assign new/old columns as primary key once column with primary key is deleted.
|
||||
| `Issue #6285 <https://github.com/pgadmin-org/pgadmin4/issues/6285>`_ - Add support for setting prepare threshold in server connection.
|
||||
| `Issue #6482 <https://github.com/pgadmin-org/pgadmin4/issues/6482>`_ - Fixed an issue where the wrong message "Current database has been moved or renamed" is displayed when debugging any function.
|
||||
| `Issue #6538 <https://github.com/pgadmin-org/pgadmin4/issues/6538>`_ - Fixed an issue where Processes tab displays wrong server name in some scenario.
|
||||
| `Issue #6579 <https://github.com/pgadmin-org/pgadmin4/issues/6579>`_ - Fix an issue where global/native keyboard shortcuts are not working when any cell of data output grid has focus.
|
||||
| `Issue #6666 <https://github.com/pgadmin-org/pgadmin4/issues/6666>`_ - Fixed query history slowness issue by storing query only for those having certain threshold max length.
|
||||
| `Issue #6674 <https://github.com/pgadmin-org/pgadmin4/issues/6674>`_ - Fix an issue where foreign table column name becomes "none" if the user changes any column data type.
|
||||
| `Issue #6718 <https://github.com/pgadmin-org/pgadmin4/issues/6718>`_ - Pin the cryptography version to fix PyO3 modules initialisation error.
|
||||
| `Issue #6790 <https://github.com/pgadmin-org/pgadmin4/issues/6790>`_ - Ensure that the backup works properly for PG 16 on the latest docker image.
|
||||
| `Issue #6799 <https://github.com/pgadmin-org/pgadmin4/issues/6799>`_ - Fixed an issue where the user is unable to select objects on the backup dialog due to tree flickering.
|
||||
| `Issue #6836 <https://github.com/pgadmin-org/pgadmin4/issues/6836>`_ - Fixed an issue where non-super PostgreSQL users are not able to terminate their own connections from dashboard.
|
||||
| `Issue #6851 <https://github.com/pgadmin-org/pgadmin4/issues/6851>`_ - Fix an issue where scale in columns is not allowed to have value as 0 or below.
|
||||
| `Issue #6858 <https://github.com/pgadmin-org/pgadmin4/issues/6858>`_ - Fix an issue in graphical explain plan where query tool crashes when the plan has parallel workers details and sort node is clicked for details.
|
||||
| `Issue #6865 <https://github.com/pgadmin-org/pgadmin4/issues/6865>`_ - Fix an issue where user login is not working if username/email contains single quote in server mode.
|
||||
@@ -44,6 +44,9 @@ Use the fields in the *General* tab to identify the server:
|
||||
Please note that once the server is shared, it's icon is changed in the
|
||||
object explorer.
|
||||
|
||||
* Use the *Shared Username* field to fill the username of the shared server
|
||||
connection. By default, it will take the username of the server being shared.
|
||||
|
||||
* Provide a comment about the server in the *Comments* field.
|
||||
|
||||
Click the *Connection* tab to continue.
|
||||
@@ -203,6 +206,12 @@ Use the fields in the *Advanced* tab to configure a connection:
|
||||
the password will not expire until your pgAdmin session does.
|
||||
Zero means the command will be executed for each new connection or reconnection that is made.
|
||||
If the generated password is not valid indefinitely, set this value to slightly before it will expire.
|
||||
* Use the *Prepare threshold* field to specify the number of times a query is
|
||||
executed before it is prepared. If it is set to 0, every query is prepared
|
||||
the first time it is executed. If it is set to blank, prepared statements are disabled
|
||||
on the connection. This is particularly useful with external connection poolers,
|
||||
such as PgBouncer, which is not compatible with prepared statements. Set this to
|
||||
blank in such cases.
|
||||
|
||||
.. note:: The password file option is only supported when pgAdmin is using libpq
|
||||
v10.0 or later to connect to the server.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
Use the *Subscription* dialog to create a subscription. A subscription defines the connection to another database and set of publications (one or more) to which it wants to subscribe.
|
||||
|
||||
The *subscription* dialog organizes the development of a subscription through the following dialog tabs: *General*, *Connection* and *With*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
The *subscription* dialog organizes the development of a subscription through the following dialog tabs: *General*, *Connection*, *SSL* and *With*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
|
||||
.. image:: images/subscription_general.png
|
||||
:alt: Subscription dialog general tab
|
||||
@@ -83,7 +83,11 @@ icon that is located to the right of each of the following fields.
|
||||
|
||||
Click the *With* tab to continue.
|
||||
|
||||
.. image:: images/subscription_with.png
|
||||
.. image:: images/subscription_with_1.png
|
||||
:alt: Subscription dialog with tab
|
||||
:align: center
|
||||
|
||||
.. image:: images/subscription_with_2.png
|
||||
:alt: Subscription dialog with tab
|
||||
:align: center
|
||||
|
||||
@@ -95,6 +99,13 @@ Use the *With* tab to define some parameters for a subscription:
|
||||
* The *Connect?* specifies whether the CREATE SUBSCRIPTION should connect to the publisher at all. By default, it is set to *Yes*. Setting this to *No* will change default values of enabled, create_slot and copy_data to *No*.
|
||||
* Use the *Slot Name* field to specify the name of the replication slot to use. By default, it uses the name of the subscription for the slot name.
|
||||
* Use the *Synchronous commit* field to override the synchronous_commit setting. By default, it is set to *off*. It is safe to use off for logical replication: If the subscriber loses transactions because of missing synchronization, the data will be sent again from the publisher.
|
||||
* Use the *Streaming* field to specify whether to enable streaming of in-progress transactions for this subscription. The default value is *off*, meaning all transactions are fully decoded on the publisher and only then sent to the subscriber as a whole. This option is available only on PostgreSQL 14 and above.
|
||||
* Use the *Binary?* switch to specify whether the subscription will request the publisher to send the data in binary format (as opposed to text). The default is *false*. This option is available only on PostgreSQL 14 and above.
|
||||
* Use the *Two phase?* switch to specify whether two-phase commit is enabled for this subscription. The default is *false*. This option is available only on PostgreSQL 15 and above.
|
||||
* Use the *Disable on error?* switch to specify whether the subscription should be automatically disabled if any errors are detected by subscription workers during data replication from the publisher. The default is *false*. This option is available only on PostgreSQL 15 and above.
|
||||
* 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.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
|
||||
@@ -394,6 +394,9 @@ Use the fields in the *Advanced* tab to define advanced features for the table:
|
||||
* Use the drop-down listbox next to *Of type* to copy the table structure from
|
||||
the specified composite type. Please note that a typed table will be dropped
|
||||
if the type is dropped (with DROP TYPE ... CASCADE).
|
||||
* Use the drop-down list box next to Access Method to specify the table access method to use to store
|
||||
the contents for the new table; the method needs to be an access method of type TABLE. This field is optional.
|
||||
This option is available from v12 and above.
|
||||
* Use the *Fill Factor* field to specify a fill factor for the table. The fill
|
||||
factor for a table is a percentage between 10 and 100. 100 (complete packing)
|
||||
is the default.
|
||||
|
||||
@@ -19,19 +19,18 @@ CA_FILE = '/etc/ssl/certs/ca-certificates.crt'
|
||||
LOG_FILE = '/dev/null'
|
||||
HELP_PATH = '../../docs'
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
'pg': '/usr/local/pgsql-15',
|
||||
'pg': '/usr/local/pgsql-16',
|
||||
'pg-16': '/usr/local/pgsql-16',
|
||||
'pg-15': '/usr/local/pgsql-15',
|
||||
'pg-14': '/usr/local/pgsql-14',
|
||||
'pg-13': '/usr/local/pgsql-13',
|
||||
'pg-12': '/usr/local/pgsql-12',
|
||||
'pg-11': '/usr/local/pgsql-11',
|
||||
'pg-10': '/usr/local/pgsql-10'
|
||||
'pg-12': '/usr/local/pgsql-12'
|
||||
}
|
||||
EOF
|
||||
|
||||
# This is a bit kludgy, but necessary as the container uses BusyBox/ash as
|
||||
# it's shell and not bash which would allow a much cleaner implementation
|
||||
for var in $(env | grep PGADMIN_CONFIG_ | cut -d "=" -f 1); do
|
||||
for var in $(env | grep "^PGADMIN_CONFIG_" | cut -d "=" -f 1); do
|
||||
# shellcheck disable=SC2086
|
||||
# shellcheck disable=SC2046
|
||||
echo ${var#PGADMIN_CONFIG_} = $(eval "echo \$$var") >> /pgadmin4/config_distro.py
|
||||
|
||||
@@ -27,11 +27,12 @@ pytz==2023.*
|
||||
speaklater3==1.*
|
||||
sqlparse==0.*
|
||||
psutil==5.9.*
|
||||
psycopg[c]==3.1.9
|
||||
psycopg[c]==3.1.12
|
||||
python-dateutil==2.*
|
||||
SQLAlchemy==2.*
|
||||
bcrypt==4.0.*
|
||||
cryptography==41.0.*
|
||||
# Pinned for #6718
|
||||
cryptography==40.0.*
|
||||
sshtunnel==0.*
|
||||
ldap3==2.*
|
||||
gssapi==1.8.*
|
||||
@@ -42,7 +43,6 @@ pywinpty==2.0.*; sys_platform=="win32"
|
||||
Authlib==1.2.*
|
||||
pyotp==2.*
|
||||
qrcode==7.*
|
||||
Pillow==9.*
|
||||
boto3==1.28.*
|
||||
botocore==1.31.*
|
||||
urllib3==1.26.*
|
||||
@@ -53,4 +53,4 @@ azure-identity==1.13.0
|
||||
google-api-python-client==2.*
|
||||
google-auth-oauthlib==1.0.0
|
||||
Werkzeug==2.2.3
|
||||
keyring==23.*
|
||||
keyring==23.*
|
||||
@@ -23,11 +23,11 @@
|
||||
"256": "assets/pgAdmin4.png"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.4.0",
|
||||
"axios": "^1.5.1",
|
||||
"bootstrap": "^4.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.42.0",
|
||||
"eslint": "^8.50.0",
|
||||
"nw": "0.77.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -47,21 +47,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint/js@npm:^8.47.0":
|
||||
version: 8.47.0
|
||||
resolution: "@eslint/js@npm:8.47.0"
|
||||
checksum: 0ef57fe27b6d4c305b33f3b2d2fee1ab397a619006f1d6f4ce5ee4746b8f03d11a4e098805a7d78601ca534cf72917d37f0ac19896c992a32e26299ecb9f9de1
|
||||
"@eslint/js@npm:8.50.0":
|
||||
version: 8.50.0
|
||||
resolution: "@eslint/js@npm:8.50.0"
|
||||
checksum: 302478f2acaaa7228729ec6a04f56641590185e1d8cd1c836a6db8a6b8009f80a57349341be9fbb9aa1721a7a569d1be3ffc598a33300d22816f11832095386c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@humanwhocodes/config-array@npm:^0.11.10":
|
||||
version: 0.11.10
|
||||
resolution: "@humanwhocodes/config-array@npm:0.11.10"
|
||||
"@humanwhocodes/config-array@npm:^0.11.11":
|
||||
version: 0.11.11
|
||||
resolution: "@humanwhocodes/config-array@npm:0.11.11"
|
||||
dependencies:
|
||||
"@humanwhocodes/object-schema": ^1.2.1
|
||||
debug: ^4.1.1
|
||||
minimatch: ^3.0.5
|
||||
checksum: 1b1302e2403d0e35bc43e66d67a2b36b0ad1119efc704b5faff68c41f791a052355b010fb2d27ef022670f550de24cd6d08d5ecf0821c16326b7dcd0ee5d5d8a
|
||||
checksum: db84507375ab77b8ffdd24f498a5b49ad6b64391d30dd2ac56885501d03964d29637e05b1ed5aefa09d57ac667e28028bc22d2da872bfcd619652fbdb5f4ca19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -205,14 +205,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"axios@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "axios@npm:1.4.0"
|
||||
"axios@npm:^1.5.1":
|
||||
version: 1.5.1
|
||||
resolution: "axios@npm:1.5.1"
|
||||
dependencies:
|
||||
follow-redirects: ^1.15.0
|
||||
form-data: ^4.0.0
|
||||
proxy-from-env: ^1.1.0
|
||||
checksum: 7fb6a4313bae7f45e89d62c70a800913c303df653f19eafec88e56cea2e3821066b8409bc68be1930ecca80e861c52aa787659df0ffec6ad4d451c7816b9386b
|
||||
checksum: 4444f06601f4ede154183767863d2b8e472b4a6bfc5253597ed6d21899887e1fd0ee2b3de792ac4f8459fe2e359d2aa07c216e45fd8b9e4e0688a6ebf48a5a8d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -618,15 +618,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint@npm:^8.42.0":
|
||||
version: 8.47.0
|
||||
resolution: "eslint@npm:8.47.0"
|
||||
"eslint@npm:^8.50.0":
|
||||
version: 8.50.0
|
||||
resolution: "eslint@npm:8.50.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": ^4.2.0
|
||||
"@eslint-community/regexpp": ^4.6.1
|
||||
"@eslint/eslintrc": ^2.1.2
|
||||
"@eslint/js": ^8.47.0
|
||||
"@humanwhocodes/config-array": ^0.11.10
|
||||
"@eslint/js": 8.50.0
|
||||
"@humanwhocodes/config-array": ^0.11.11
|
||||
"@humanwhocodes/module-importer": ^1.0.1
|
||||
"@nodelib/fs.walk": ^1.2.8
|
||||
ajv: ^6.12.4
|
||||
@@ -661,7 +661,7 @@ __metadata:
|
||||
text-table: ^0.2.0
|
||||
bin:
|
||||
eslint: bin/eslint.js
|
||||
checksum: 1988617f703eadc5c7540468d54dc8e5171cf2bb9483f6172799cd1ff54a9a5e4470f003784e8cef92687eaa14de37172732787040e67817581a20bcb9c15970
|
||||
checksum: 9ebfe5615dc84700000d218e32ddfdcfc227ca600f65f18e5541ec34f8902a00356a9a8804d9468fd6c8637a5ef6a3897291dad91ba6579d5b32ffeae5e31768
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1414,9 +1414,9 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "pgadmin4@workspace:."
|
||||
dependencies:
|
||||
axios: ^1.4.0
|
||||
axios: ^1.5.1
|
||||
bootstrap: ^4.5.3
|
||||
eslint: ^8.42.0
|
||||
eslint: ^8.50.0
|
||||
nw: 0.77.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -50,7 +50,7 @@ APP_ICON = 'pg-icon'
|
||||
|
||||
# Application version number components
|
||||
APP_RELEASE = 7
|
||||
APP_REVISION = 6
|
||||
APP_REVISION = 8
|
||||
|
||||
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
|
||||
# for GA releases.
|
||||
@@ -59,7 +59,7 @@ APP_SUFFIX = ''
|
||||
# Numeric application version for upgrade checks. Should be in the format:
|
||||
# [X]XYYZZ, where X is the release version, Y is the revision, with a leading
|
||||
# zero if needed, and Z represents the suffix, with a leading zero if needed
|
||||
APP_VERSION_INT = 70600
|
||||
APP_VERSION_INT = 70800
|
||||
|
||||
# DO NOT CHANGE!
|
||||
# The application version string, constructed from the components
|
||||
@@ -477,14 +477,12 @@ STORAGE_DIR = os.path.join(DATA_DIR, 'storage')
|
||||
##########################################################################
|
||||
DEFAULT_BINARY_PATHS = {
|
||||
"pg": "",
|
||||
"pg-11": "",
|
||||
"pg-12": "",
|
||||
"pg-13": "",
|
||||
"pg-14": "",
|
||||
"pg-15": "",
|
||||
"pg-16": "",
|
||||
"ppas": "",
|
||||
"ppas-11": "",
|
||||
"ppas-12": "",
|
||||
"ppas-13": "",
|
||||
"ppas-14": "",
|
||||
@@ -793,6 +791,30 @@ OAUTH2_CONFIG = [
|
||||
'OAUTH2_ICON': None,
|
||||
# UI button colour, ex: #0000ff
|
||||
'OAUTH2_BUTTON_COLOR': None,
|
||||
# The additional claims to check on user ID Token. This is useful to
|
||||
# provide additional authorization checks before allowing access.
|
||||
# Example for GitLab: allowing all maintainers teams, and a specific
|
||||
# developers group to access pgadmin:
|
||||
# 'OAUTH2_ADDITIONAL_CLAIMS': {
|
||||
# 'https://gitlab.org/claims/groups/maintainer': [
|
||||
# 'kuberheads/applications',
|
||||
# 'kuberheads/dba',
|
||||
# 'kuberheads/support'
|
||||
# ],
|
||||
# 'https://gitlab.org/claims/groups/developer': [
|
||||
# 'kuberheads/applications/team01'
|
||||
# ],
|
||||
# }
|
||||
# Example for AzureAD:
|
||||
# 'OAUTH2_ADDITIONAL_CLAIMS': {
|
||||
# 'groups': ["0760b6cf-170e-4a14-91b3-4b78e0739963"],
|
||||
# 'wids': ["cf1c38e5-3621-4004-a7cb-879624dced7c"],
|
||||
# }
|
||||
# Example for any key value string check:
|
||||
# 'OAUTH2_ADDITIONAL_CLAIMS': {
|
||||
# 'group': "0760b6cf-170e-4a14-91b3-4b78e0739963",
|
||||
# }
|
||||
'OAUTH2_ADDITIONAL_CLAIMS': None,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Add support for prepare_threshold param
|
||||
https://www.psycopg.org/psycopg3/docs/advanced/prepare.html#prepared-statements
|
||||
|
||||
Revision ID: 44b9ce549393
|
||||
Revises: 9426ad06a63b
|
||||
Create Date: 2023-10-12 12:15:01.757931
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '44b9ce549393'
|
||||
down_revision = '9426ad06a63b'
|
||||
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('prepare_threshold', sa.Integer(),
|
||||
nullable=True))
|
||||
|
||||
with op.batch_alter_table("sharedserver") as batch_op:
|
||||
batch_op.add_column(sa.Column('prepare_threshold', sa.Integer(),
|
||||
nullable=True))
|
||||
|
||||
# get metadata from current connection
|
||||
meta = sa.MetaData()
|
||||
# define table representation
|
||||
meta.reflect(op.get_bind(), only=('server', 'sharedserver'))
|
||||
table = sa.Table('server', meta)
|
||||
op.execute(
|
||||
table.update().values(prepare_threshold=5)
|
||||
)
|
||||
table = sa.Table('sharedserver', meta)
|
||||
op.execute(
|
||||
table.update().values(prepare_threshold=5)
|
||||
)
|
||||
|
||||
def downgrade():
|
||||
# pgAdmin only upgrades, downgrade not implemented.
|
||||
pass
|
||||
@@ -0,0 +1,40 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
""" Add the new column for shared server username and change
|
||||
autoincrement in server table
|
||||
Revision ID: 9426ad06a63b
|
||||
Revises: f656e56dfdc8
|
||||
Create Date: 2023-10-09 15:09:50.773035
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '9426ad06a63b'
|
||||
down_revision = 'f656e56dfdc8'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Added sqlite_autoincrement to force sqlite use auto increment instead of
|
||||
# last row id for next record. For future server table changes, we need to
|
||||
# add table_kwargs={'sqlite_autoincrement': True} as a param to
|
||||
# batch_alter_table
|
||||
with op.batch_alter_table(
|
||||
"server", table_kwargs={'sqlite_autoincrement': True}) as batch_op:
|
||||
batch_op.alter_column('id', autoincrement=True)
|
||||
batch_op.add_column(sa.Column('shared_username', sa.String(64), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
# pgAdmin only upgrades, downgrade not implemented.
|
||||
pass
|
||||
@@ -35,7 +35,7 @@
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"enzyme": "^3.11.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"exports-loader": "^4.0.0",
|
||||
"html-react-parser": "^4.2.0",
|
||||
@@ -43,7 +43,6 @@
|
||||
"imagemin": "^8.0.1",
|
||||
"imagemin-mozjpeg": "^10.0.0",
|
||||
"imagemin-optipng": "^8.0.0",
|
||||
"imagemin-pngquant": "^9.0.2",
|
||||
"imports-loader": "^4.0.1",
|
||||
"is-docker": "^2.1.1",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
@@ -77,7 +76,7 @@
|
||||
"typescript": "^3.2.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webfonts-loader": "^8.0.1",
|
||||
"webpack": "^5.76.3",
|
||||
"webpack": "^5.88.2",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-cli": "^4.5.0",
|
||||
"yarn-audit-html": "4.0.0"
|
||||
@@ -117,7 +116,7 @@
|
||||
"dagre": "^0.8.4",
|
||||
"date-fns": "^2.24.0",
|
||||
"diff-arrays-of-objects": "^1.1.8",
|
||||
"html2canvas": "^1.0.0-rc.7",
|
||||
"html-to-image": "^1.11.11",
|
||||
"immutability-helper": "^3.0.0",
|
||||
"insert-if": "^1.1.0",
|
||||
"ip-address": "^7.1.0",
|
||||
@@ -138,10 +137,11 @@
|
||||
"pathfinding": "^0.4.18",
|
||||
"paths-js": "^0.4.9",
|
||||
"popper.js": "^1.16.1",
|
||||
"postcss": "^8.2.15",
|
||||
"postcss": "^8.4.31",
|
||||
"raf": "^3.4.1",
|
||||
"rc-dock": "^3.2.9",
|
||||
"react": "^17.0.1",
|
||||
"react-arborist": "^3.2.0",
|
||||
"react-aspen": "^1.1.0",
|
||||
"react-checkbox-tree": "^1.7.2",
|
||||
"react-data-grid": "https://github.com/pgadmin-org/react-data-grid.git#200d2f5e02de694e3e9ffbe177c279bc40240fb8",
|
||||
|
||||
@@ -18,15 +18,15 @@ from flask import current_app, flash, Response, request, url_for, \
|
||||
session, redirect, render_template
|
||||
from flask_babel import gettext
|
||||
from flask_security.views import _security, _ctx
|
||||
from flask_security.utils import get_post_logout_redirect, logout_user,\
|
||||
config_value
|
||||
from flask_security.utils import logout_user, config_value
|
||||
|
||||
from flask_login import current_user
|
||||
from flask_socketio import disconnect, ConnectionRefusedError
|
||||
|
||||
|
||||
from pgadmin.model import db, User
|
||||
from pgadmin.utils import PgAdminModule, get_safe_post_login_redirect
|
||||
from pgadmin.utils import PgAdminModule, get_safe_post_login_redirect, \
|
||||
get_safe_post_logout_redirect
|
||||
from pgadmin.utils.constants import KERBEROS, INTERNAL, OAUTH2, LDAP,\
|
||||
MessageType
|
||||
from pgadmin.authenticate.registry import AuthSourceRegistry
|
||||
@@ -135,7 +135,7 @@ def _login():
|
||||
'Administrator.'),
|
||||
MessageType.WARNING)
|
||||
logout_user()
|
||||
return redirect(get_post_logout_redirect())
|
||||
return redirect(get_safe_post_logout_redirect())
|
||||
|
||||
# Validate the user
|
||||
if not auth_obj.validate():
|
||||
@@ -161,7 +161,7 @@ def _login():
|
||||
flash_login_attempt_error = None
|
||||
flash(error, MessageType.WARNING)
|
||||
|
||||
return redirect(get_post_logout_redirect())
|
||||
return redirect(get_safe_post_logout_redirect())
|
||||
|
||||
# Authenticate the user
|
||||
status, msg = auth_obj.authenticate()
|
||||
@@ -177,7 +177,7 @@ def _login():
|
||||
'authenticate.kerberos_login'), url_for('browser.index')))
|
||||
|
||||
flash(msg, MessageType.ERROR)
|
||||
return redirect(get_post_logout_redirect())
|
||||
return redirect(get_safe_post_logout_redirect())
|
||||
|
||||
session['auth_source_manager'] = current_auth_obj
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ class TOTPAuthenticator(BaseMFAuth):
|
||||
|
||||
img = qrcode.make(uri)
|
||||
buffered = BytesIO()
|
||||
img.save(buffered, format="JPEG")
|
||||
img.save(buffered)
|
||||
img_base64 = base64.b64encode(buffered.getvalue())
|
||||
|
||||
return dict(
|
||||
|
||||
@@ -16,13 +16,14 @@ from flask import current_app, url_for, session, request,\
|
||||
redirect, Flask, flash
|
||||
from flask_babel import gettext
|
||||
from flask_security import login_user, current_user
|
||||
from flask_security.utils import get_post_logout_redirect, logout_user
|
||||
from flask_security.utils import logout_user
|
||||
|
||||
from pgadmin.authenticate.internal import BaseAuthentication
|
||||
from pgadmin.model import User
|
||||
from pgadmin.tools.user_management import create_user
|
||||
from pgadmin.utils.constants import OAUTH2, MessageType
|
||||
from pgadmin.utils import PgAdminModule, get_safe_post_login_redirect
|
||||
from pgadmin.utils import PgAdminModule, get_safe_post_login_redirect, \
|
||||
get_safe_post_logout_redirect
|
||||
from pgadmin.utils.csrf import pgCSRFProtect
|
||||
from pgadmin.model import db
|
||||
|
||||
@@ -69,11 +70,11 @@ def init_app(app):
|
||||
@pgCSRFProtect.exempt
|
||||
def oauth_logout():
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(get_post_logout_redirect())
|
||||
return redirect(get_safe_post_logout_redirect())
|
||||
for key in list(session.keys()):
|
||||
session.pop(key)
|
||||
logout_user()
|
||||
return redirect(get_post_logout_redirect())
|
||||
return redirect(get_safe_post_logout_redirect())
|
||||
|
||||
app.register_blueprint(blueprint)
|
||||
app.login_manager.logout_view = OAUTH2_LOGOUT
|
||||
@@ -150,6 +151,26 @@ class OAuth2Authentication(BaseAuthentication):
|
||||
current_app.logger.exception(error_msg)
|
||||
return False, gettext(error_msg)
|
||||
|
||||
additinal_claims = None
|
||||
if 'OAUTH2_ADDITIONAL_CLAIMS' in self.oauth2_config[
|
||||
self.oauth2_current_client]:
|
||||
additinal_claims = self.oauth2_config[
|
||||
self.oauth2_current_client
|
||||
]['OAUTH2_ADDITIONAL_CLAIMS']
|
||||
|
||||
(valid, reason) = self.__is_additional_claims_valid(profile,
|
||||
additinal_claims)
|
||||
|
||||
if not valid:
|
||||
return_msg = "The user is not authorized to login" \
|
||||
" based on the claims in the profile." \
|
||||
" Please contact your administrator."
|
||||
audit_msg = f"The authenticated user {username} is not" \
|
||||
" authorized to access pgAdmin based on OAUTH2 config. " \
|
||||
f"Reason: {reason}"
|
||||
current_app.logger.warning(audit_msg)
|
||||
return False, return_msg
|
||||
|
||||
user, msg = self.__auto_create_user(username, email)
|
||||
if user:
|
||||
user = db.session.query(User).filter_by(
|
||||
@@ -203,3 +224,24 @@ class OAuth2Authentication(BaseAuthentication):
|
||||
})
|
||||
|
||||
return True, {'username': username}
|
||||
|
||||
def __is_additional_claims_valid(self, profile, additional_claims):
|
||||
if additional_claims is None:
|
||||
reason = "Additional claim config is None, no check to do."
|
||||
return (True, reason)
|
||||
if not isinstance(additional_claims, dict):
|
||||
reason = "Additional claim check config is not a dict."
|
||||
return (False, reason)
|
||||
if additional_claims.keys() is None:
|
||||
reason = "Additional claim check config dict is empty."
|
||||
return (False, reason)
|
||||
for key in additional_claims.keys():
|
||||
claim = profile.get(key)
|
||||
if claim is None:
|
||||
continue
|
||||
authorized_claims = additional_claims.get(key)
|
||||
if any(item in authorized_claims for item in claim):
|
||||
reason = "Claim match found. Authorizing"
|
||||
return (True, reason)
|
||||
reason = f"Profile does not have any of given additional claims."
|
||||
return (False, reason)
|
||||
@@ -30,13 +30,13 @@ from flask_babel import gettext
|
||||
from flask_gravatar import Gravatar
|
||||
from flask_login import current_user, login_required
|
||||
from flask_login.utils import login_url
|
||||
from flask_security.changeable import change_user_password
|
||||
from flask_security.changeable import send_password_changed_notice
|
||||
from flask_security.decorators import anonymous_user_required
|
||||
from flask_security.recoverable import reset_password_token_status, \
|
||||
generate_reset_password_token, update_password
|
||||
from flask_security.signals import reset_password_instructions_sent
|
||||
from flask_security.utils import config_value, do_flash, get_url, \
|
||||
get_message, slash_url_suffix, login_user, send_mail, \
|
||||
get_message, slash_url_suffix, login_user, send_mail, hash_password, \
|
||||
get_post_logout_redirect
|
||||
from flask_security.views import _security, view_commit, _ctx
|
||||
from werkzeug.datastructures import MultiDict
|
||||
@@ -668,7 +668,7 @@ def utils():
|
||||
mfa_enabled=is_mfa_enabled(),
|
||||
is_admin=current_user.has_role("Administrator"),
|
||||
login_url=login_url,
|
||||
username=current_user.username,
|
||||
username=current_user.username.replace("'","\\'"),
|
||||
auth_source=auth_source,
|
||||
heartbeat_timeout=config.SERVER_HEARTBEAT_TIMEOUT,
|
||||
password_length_min=config.PASSWORD_LENGTH_MIN,
|
||||
@@ -1071,30 +1071,27 @@ if hasattr(config, 'SECURITY_CHANGEABLE') and config.SECURITY_CHANGEABLE:
|
||||
}
|
||||
elif req_json:
|
||||
form = form_class(MultiDict(req_json))
|
||||
if form.validate_on_submit():
|
||||
if form.validate():
|
||||
errormsg = None
|
||||
# change_user_password from flask-security logs out the user
|
||||
# this is undesirable, so change password on own
|
||||
try:
|
||||
change_user_password(current_user._get_current_object(),
|
||||
form.new_password.data,
|
||||
autologin=False)
|
||||
except SOCKETErrorException as e:
|
||||
# Handle socket errors which are not covered by
|
||||
# SMTPExceptions.
|
||||
logging.exception(str(e), exc_info=True)
|
||||
errormsg = gettext(SMTP_SOCKET_ERROR).format(e)
|
||||
except (SMTPConnectError, SMTPResponseException,
|
||||
SMTPServerDisconnected, SMTPDataError, SMTPHeloError,
|
||||
SMTPException, SMTPAuthenticationError,
|
||||
SMTPSenderRefused, SMTPRecipientsRefused) as ex:
|
||||
# Handle smtp specific exceptions.
|
||||
logging.exception(str(ex), exc_info=True)
|
||||
errormsg = gettext(SMTP_ERROR).format(ex)
|
||||
user = User.query.filter(
|
||||
User.fs_uniquifier == current_user.fs_uniquifier)\
|
||||
.first()
|
||||
user.password = hash_password(form.new_password.data)
|
||||
|
||||
try:
|
||||
send_password_changed_notice(user)
|
||||
except Exception as _:
|
||||
# No need to throw error if failed in sending email
|
||||
pass
|
||||
except Exception as e:
|
||||
# Handle other exceptions.
|
||||
logging.exception(str(e), exc_info=True)
|
||||
errormsg = gettext(PASS_ERROR).format(e)
|
||||
|
||||
if request.get_json(silent=True) is None and errormsg is None:
|
||||
if errormsg is None:
|
||||
old_key = get_crypt_key()[1]
|
||||
set_crypt_key(form.new_password.data, False)
|
||||
|
||||
@@ -1103,12 +1100,12 @@ if hasattr(config, 'SECURITY_CHANGEABLE') and config.SECURITY_CHANGEABLE:
|
||||
reencrpyt_server_passwords(
|
||||
current_user.id, old_key, form.new_password.data)
|
||||
|
||||
return redirect(get_url(_security.post_change_view) or
|
||||
get_url(_security.post_login_view))
|
||||
db.session.commit()
|
||||
elif errormsg is not None:
|
||||
return internal_server_error(errormsg)
|
||||
else:
|
||||
return bad_request(list(form.errors.values())[0][0])
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext('pgAdmin user password changed successfully')
|
||||
|
||||
@@ -176,6 +176,7 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
server.username = sharedserver.username
|
||||
server.server_owner = sharedserver.server_owner
|
||||
server.password = sharedserver.password
|
||||
server.prepare_threshold = sharedserver.prepare_threshold
|
||||
|
||||
return server
|
||||
|
||||
@@ -376,7 +377,7 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
host=data.host,
|
||||
port=data.port,
|
||||
maintenance_db=data.maintenance_db,
|
||||
username=None,
|
||||
username=data.shared_username,
|
||||
save_password=0,
|
||||
comment=None,
|
||||
role=data.role,
|
||||
@@ -390,7 +391,8 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
tunnel_authentication=0,
|
||||
tunnel_identity_file=None,
|
||||
shared=True,
|
||||
connection_params=data.connection_params
|
||||
connection_params=data.connection_params,
|
||||
prepare_threshold=data.prepare_threshold
|
||||
)
|
||||
db.session.add(shared_server)
|
||||
db.session.commit()
|
||||
@@ -399,8 +401,7 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
db.session.delete(shared_server)
|
||||
db.session.commit()
|
||||
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def get_shared_server(server, gid):
|
||||
@@ -814,8 +815,10 @@ class ServerNode(PGChildNodeView):
|
||||
'tunnel_authentication': 'tunnel_authentication',
|
||||
'tunnel_identity_file': 'tunnel_identity_file',
|
||||
'shared': 'shared',
|
||||
'shared_username': 'shared_username',
|
||||
'kerberos_conn': 'kerberos_conn',
|
||||
'connection_params': 'connection_params'
|
||||
'connection_params': 'connection_params',
|
||||
'prepare_threshold': 'prepare_threshold'
|
||||
}
|
||||
|
||||
disp_lbl = {
|
||||
@@ -850,6 +853,10 @@ class ServerNode(PGChildNodeView):
|
||||
errormsg=gettext('Not a valid Host address')
|
||||
)
|
||||
|
||||
# remove the shared username if shared is updated to False
|
||||
if 'shared' in data and data['shared'] is False:
|
||||
data['shared_username'] = ''
|
||||
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
@@ -1073,6 +1080,8 @@ class ServerNode(PGChildNodeView):
|
||||
'port': server.port,
|
||||
'db': server.maintenance_db,
|
||||
'shared': server.shared if config.SERVER_MODE else None,
|
||||
'shared_username': server.shared_username
|
||||
if config.SERVER_MODE else None,
|
||||
'username': server.username,
|
||||
'gid': str(server.servergroup_id),
|
||||
'group-name': sg.name if (sg and sg.name) else gettext('Servers'),
|
||||
@@ -1102,7 +1111,8 @@ class ServerNode(PGChildNodeView):
|
||||
'gss_encrypted': manager.gss_encrypted,
|
||||
'cloud_status': server.cloud_status,
|
||||
'connection_params': connection_params,
|
||||
'connection_string': manager.display_connection_string
|
||||
'connection_string': manager.display_connection_string,
|
||||
'prepare_threshold': server.prepare_threshold
|
||||
}
|
||||
|
||||
return ajax_response(response)
|
||||
@@ -1192,10 +1202,12 @@ class ServerNode(PGChildNodeView):
|
||||
False) else 0,
|
||||
tunnel_identity_file=data.get('tunnel_identity_file', None),
|
||||
shared=data.get('shared', None),
|
||||
shared_username=data.get('shared_username', None),
|
||||
passexec_cmd=data.get('passexec_cmd', None),
|
||||
passexec_expiration=data.get('passexec_expiration', None),
|
||||
kerberos_conn=1 if data.get('kerberos_conn', False) else 0,
|
||||
connection_params=connection_params
|
||||
connection_params=connection_params,
|
||||
prepare_threshold=data.get('prepare_threshold', None)
|
||||
)
|
||||
db.session.add(server)
|
||||
db.session.commit()
|
||||
|
||||
@@ -193,6 +193,10 @@ class DatabaseView(PGChildNodeView):
|
||||
{'get': 'get_ctypes'},
|
||||
{'get': 'get_ctypes'}
|
||||
],
|
||||
'get_icu_locale': [
|
||||
{'get': 'get_icu_locale'},
|
||||
{'get': 'get_icu_locale'}
|
||||
],
|
||||
'vopts': [
|
||||
{}, {'get': 'variable_options'}
|
||||
],
|
||||
@@ -634,7 +638,7 @@ class DatabaseView(PGChildNodeView):
|
||||
"""
|
||||
This function to return list of available collation/character types
|
||||
"""
|
||||
res = [{'label': '', 'value': ''}]
|
||||
res = []
|
||||
default_list = ['C', 'POSIX']
|
||||
for val in default_list:
|
||||
res.append(
|
||||
@@ -656,6 +660,28 @@ class DatabaseView(PGChildNodeView):
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition(action="get_icu_locale")
|
||||
def get_icu_locale(self, gid, sid, did=None):
|
||||
"""
|
||||
This function is used to get the list of icu locale
|
||||
"""
|
||||
res = []
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'get_icu_locale.sql'])
|
||||
)
|
||||
status, rset = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
res.append(
|
||||
{'label': row['colliculocale'], 'value': row['colliculocale']})
|
||||
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition(action="create")
|
||||
def create(self, gid, sid):
|
||||
"""Create the database."""
|
||||
@@ -1230,6 +1256,12 @@ class DatabaseView(PGChildNodeView):
|
||||
did=did, conn=conn, last_system_oid=0,
|
||||
show_system_objects=False,
|
||||
)
|
||||
|
||||
# try to connect the db if not connected
|
||||
# don't delete the below code as it is needed for Database RESQL tests.
|
||||
if not conn.connected():
|
||||
conn.connect()
|
||||
|
||||
status, res = conn.execute_dict(SQL)
|
||||
|
||||
if not status:
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"""Implements the Foreign Table Module."""
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import re
|
||||
from functools import wraps
|
||||
|
||||
import json
|
||||
from flask import render_template, make_response, request, jsonify, \
|
||||
from flask import render_template, request, jsonify, \
|
||||
current_app
|
||||
from flask_babel import gettext
|
||||
|
||||
@@ -33,6 +33,10 @@ from pgadmin.utils.compile_template_name import compile_template_path
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
|
||||
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
|
||||
|
||||
|
||||
class ForeignTableModule(SchemaChildModule):
|
||||
@@ -88,6 +92,10 @@ class ForeignTableModule(SchemaChildModule):
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
constraints import blueprint as module
|
||||
self.submodules.append(module)
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas. \
|
||||
foreign_tables.foreign_table_columns import \
|
||||
foreign_table_column_blueprint as module
|
||||
self.submodules.append(module)
|
||||
super().register(app, options)
|
||||
|
||||
|
||||
@@ -184,6 +192,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
node_type = blueprint.node_type
|
||||
node_label = "Foreign Table"
|
||||
BASE_TEMPLATE_PATH = 'foreign_tables/sql/#{0}#'
|
||||
double_newline = '\n\n'
|
||||
pattern = '\n{2,}'
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
@@ -216,6 +226,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
'get_foreign_servers': [{'get': 'get_foreign_servers'},
|
||||
{'get': 'get_foreign_servers'}],
|
||||
'get_tables': [{'get': 'get_tables'}, {'get': 'get_tables'}],
|
||||
'set_trigger': [{'put': 'enable_disable_triggers'}],
|
||||
'get_columns': [{'get': 'get_columns'}, {'get': 'get_columns'}],
|
||||
'select_sql': [{'get': 'select_sql'}],
|
||||
'insert_sql': [{'get': 'insert_sql'}],
|
||||
@@ -398,6 +409,17 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
self.template_path = \
|
||||
self.BASE_TEMPLATE_PATH.format(self.manager.version)
|
||||
|
||||
self.foreign_table_column_template_path = compile_template_path(
|
||||
'foreign_table_columns/sql', self.manager.version)
|
||||
|
||||
self.column_template_path = compile_template_path(
|
||||
'columns/sql', self.manager.version)
|
||||
|
||||
# Template for trigger node
|
||||
self.trigger_template_path = \
|
||||
'triggers/sql/{0}/#{1}#'.format(self.manager.server_type,
|
||||
self.manager.version)
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return wrap
|
||||
@@ -451,7 +473,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-foreign_table",
|
||||
description=row['description']
|
||||
description=row['description'],
|
||||
tigger_count=row['triggercount'],
|
||||
has_enable_triggers=row['has_enable_triggers'],
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
@@ -911,6 +935,11 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
|
||||
SQL = sql_header + SQL
|
||||
|
||||
trigger_sql = self._get_resql_for_triggers(
|
||||
foid, data['basensp'], data['name'])
|
||||
|
||||
SQL = SQL + trigger_sql
|
||||
|
||||
return ajax_response(response=SQL.strip('\n'))
|
||||
|
||||
@check_precondition
|
||||
@@ -1005,9 +1034,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
:return:
|
||||
"""
|
||||
for c in data['columns']['changed']:
|
||||
old_col_options = c['attfdwoptions'] = []
|
||||
if 'attfdwoptions' in c and c['attfdwoptions']:
|
||||
old_col_options = c['attfdwoptions']
|
||||
old_col_options = []
|
||||
if 'coloptions' in c and c['coloptions']:
|
||||
old_col_options = c['coloptions']
|
||||
|
||||
old_col_frmt_options = {}
|
||||
|
||||
@@ -1082,7 +1111,13 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
data['is_schema_diff'] = True
|
||||
old_data['columns_for_schema_diff'] = old_data['columns']
|
||||
|
||||
self._format_columns_data(data, old_data)
|
||||
# If name is not present in request data
|
||||
if 'name' not in data:
|
||||
data['name'] = old_data['name']
|
||||
|
||||
# If name if not present
|
||||
if 'schema' not in data:
|
||||
data['schema'] = old_data['basensp']
|
||||
|
||||
# Parse Privileges
|
||||
ForeignTableView._parse_privileges(data)
|
||||
@@ -1102,6 +1137,37 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
"/".join([self.template_path, self._UPDATE_SQL]),
|
||||
data=data, o_data=old_data, conn=self.conn
|
||||
)
|
||||
|
||||
# Removes trailing new lines
|
||||
if sql:
|
||||
sql = sql.strip('\n') + self.double_newline
|
||||
|
||||
# Parse/Format columns & create sql
|
||||
if 'columns' in data:
|
||||
# Parse the data coming from client
|
||||
data = column_utils.parse_format_columns(data, mode='edit')
|
||||
|
||||
columns = data['columns']
|
||||
column_sql = '\n'
|
||||
|
||||
# If column(s) is/are deleted
|
||||
column_sql = self._check_for_column_delete(columns, data,
|
||||
column_sql)
|
||||
|
||||
# If column(s) is/are changed
|
||||
column_sql = self._check_for_column_update(columns, data,
|
||||
column_sql, foid)
|
||||
|
||||
# If column(s) is/are added
|
||||
column_sql = self._check_for_column_add(columns, data,
|
||||
column_sql)
|
||||
|
||||
# Combine all the SQL together
|
||||
sql += column_sql.strip('\n')
|
||||
|
||||
sql = re.sub(self.pattern, self.double_newline, sql)
|
||||
sql = sql.strip('\n')
|
||||
|
||||
return sql, data['name'] if 'name' in data else old_data['name']
|
||||
else:
|
||||
data['columns'] = self._format_columns(data['columns'])
|
||||
@@ -1116,6 +1182,84 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
conn=self.conn)
|
||||
return sql, data['name']
|
||||
|
||||
def _check_for_column_delete(self, columns, data, column_sql):
|
||||
# If column(s) is/are deleted
|
||||
if 'deleted' in columns:
|
||||
for c in columns['deleted']:
|
||||
c['schema'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
# Sql for drop column
|
||||
if 'inheritedfrom' not in c or \
|
||||
('inheritedfrom' in c and c['inheritedfrom'] is None):
|
||||
column_sql += render_template("/".join(
|
||||
[self.foreign_table_column_template_path,
|
||||
self._DELETE_SQL]),
|
||||
data=c, conn=self.conn).strip('\n') + \
|
||||
self.double_newline
|
||||
return column_sql
|
||||
|
||||
def _check_for_column_update(self, columns, data, column_sql, tid):
|
||||
# Here we will be needing previous properties of column
|
||||
# so that we can compare & update it
|
||||
if 'changed' in columns:
|
||||
for c in columns['changed']:
|
||||
c['schema'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
|
||||
properties_sql = render_template(
|
||||
"/".join([self.column_template_path,
|
||||
self._PROPERTIES_SQL]),
|
||||
tid=tid,
|
||||
clid=c['attnum'] if 'attnum' in c else None,
|
||||
show_sys_objects=self.blueprint.show_system_objects
|
||||
)
|
||||
|
||||
status, res = self.conn.execute_dict(properties_sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
old_col_data = res['rows'][0]
|
||||
|
||||
old_col_data['cltype'], \
|
||||
old_col_data['hasSqrBracket'] = \
|
||||
column_utils.type_formatter(old_col_data['cltype'])
|
||||
old_col_data = \
|
||||
column_utils.convert_length_precision_to_string(
|
||||
old_col_data)
|
||||
old_col_data = column_utils.fetch_length_precision(
|
||||
old_col_data)
|
||||
|
||||
old_col_data['cltype'] = \
|
||||
DataTypeReader.parse_type_name(
|
||||
old_col_data['cltype'])
|
||||
|
||||
# Sql for alter column
|
||||
if 'inheritedfrom' not in c and \
|
||||
'inheritedfromtable' not in c:
|
||||
column_sql += render_template("/".join(
|
||||
[self.foreign_table_column_template_path,
|
||||
self._UPDATE_SQL]),
|
||||
data=c, o_data=old_col_data, conn=self.conn
|
||||
).strip('\n') + self.double_newline
|
||||
return column_sql
|
||||
|
||||
def _check_for_column_add(self, columns, data, column_sql):
|
||||
# If column(s) is/are added
|
||||
if 'added' in columns:
|
||||
for c in columns['added']:
|
||||
c['schema'] = data['schema']
|
||||
c['table'] = data['name']
|
||||
|
||||
c = column_utils.convert_length_precision_to_string(c)
|
||||
|
||||
if 'inheritedfrom' not in c and \
|
||||
'inheritedfromtable' not in c:
|
||||
column_sql += render_template("/".join(
|
||||
[self.foreign_table_column_template_path,
|
||||
self._CREATE_SQL]),
|
||||
data=c, conn=self.conn).strip('\n') + \
|
||||
self.double_newline
|
||||
return column_sql
|
||||
|
||||
@check_precondition
|
||||
def dependents(self, gid, sid, did, scid, foid):
|
||||
"""
|
||||
@@ -1160,15 +1304,14 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
"""
|
||||
cols = []
|
||||
for c in columns:
|
||||
if len(c) > 0:
|
||||
if '[]' in c['datatype']:
|
||||
c['datatype'] = c['datatype'].replace('[]', '')
|
||||
if len(c) > 0 and 'cltype' in c:
|
||||
if '[]' in c['cltype']:
|
||||
c['cltype'] = c['cltype'].replace('[]', '')
|
||||
c['isArrayType'] = True
|
||||
else:
|
||||
c['isArrayType'] = False
|
||||
cols.append(c)
|
||||
|
||||
return cols
|
||||
return cols if cols else columns
|
||||
|
||||
def _fetch_properties(self, gid, sid, did, scid, foid, inherits=False, ):
|
||||
"""
|
||||
@@ -1238,18 +1381,52 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=cols)
|
||||
|
||||
self._get_datatype_precision(cols)
|
||||
# Fetch length and precision data
|
||||
for col in cols['rows']:
|
||||
column_utils.fetch_length_precision(col)
|
||||
|
||||
if 'attoptions' in col and col['attoptions'] != '':
|
||||
col['attoptions'] = column_utils.parse_column_variables(
|
||||
col['attoptions'])
|
||||
|
||||
if 'attfdwoptions' in col and col['attfdwoptions'] != '':
|
||||
col['coloptions'] = column_utils.parse_options_for_column(
|
||||
col['attfdwoptions'])
|
||||
|
||||
self._get_edit_types(cols['rows'])
|
||||
|
||||
if cols and 'rows' in cols:
|
||||
data['columns'] = cols['rows']
|
||||
|
||||
# Get Inherited table names from their OID
|
||||
is_error, errmsg = self._get_inherited_table_name(data, inherits)
|
||||
|
||||
if is_error:
|
||||
return False, internal_server_error(errormsg=errmsg)
|
||||
|
||||
return True, data
|
||||
|
||||
def _get_edit_types(self, cols):
|
||||
edit_types = {}
|
||||
for col in cols:
|
||||
edit_types[col['atttypid']] = []
|
||||
|
||||
if len(cols) > 0:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'edit_mode_types_multi.sql']),
|
||||
type_ids=",".join(map(lambda x: str(x),
|
||||
edit_types.keys())))
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
for row in res['rows']:
|
||||
edit_types[row['main_oid']] = sorted(row['edit_types'])
|
||||
|
||||
for column in cols:
|
||||
edit_type_list = edit_types[column['atttypid']]
|
||||
edit_type_list.append(column['fulltype'])
|
||||
column['edit_types'] = sorted(edit_type_list)
|
||||
column['cltype'] = \
|
||||
DataTypeReader.parse_type_name(column['cltype'])
|
||||
|
||||
def _get_datatype_precision(self, cols):
|
||||
"""
|
||||
The Length and the precision of the Datatype should be separated.
|
||||
@@ -1262,11 +1439,11 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
substr = self.extract_type_length_precision(c)
|
||||
typlen = substr.split(",")
|
||||
if len(typlen) > 1:
|
||||
c['typlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['precision'] = self.convert_precision_to_int(typlen)
|
||||
c['attlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['attprecision'] = self.convert_precision_to_int(typlen)
|
||||
else:
|
||||
c['typlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['precision'] = None
|
||||
c['attlen'] = self.convert_typlen_to_int(typlen)
|
||||
c['attprecision'] = None
|
||||
|
||||
# Get formatted Column Options
|
||||
if 'attfdwoptions' in c and c['attfdwoptions'] != '':
|
||||
@@ -1393,7 +1570,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
|
||||
columns = []
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
|
||||
if len(columns) > 0:
|
||||
columns = ", ".join(columns)
|
||||
@@ -1434,7 +1611,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
# Now we have all list of columns which we need
|
||||
if 'columns' in data:
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
values.append('?')
|
||||
|
||||
if len(columns) > 0:
|
||||
@@ -1475,7 +1652,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
# Now we have all list of columns which we need
|
||||
if 'columns' in data:
|
||||
for c in data['columns']:
|
||||
columns.append(self.qtIdent(self.conn, c['attname']))
|
||||
columns.append(self.qtIdent(self.conn, c['name']))
|
||||
|
||||
if len(columns) > 0:
|
||||
if len(columns) == 1:
|
||||
@@ -1676,6 +1853,92 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
||||
|
||||
data['ftoptions'] = tmp_ftoptions
|
||||
|
||||
@check_precondition
|
||||
def enable_disable_triggers(self, gid, sid, did, scid, foid):
|
||||
"""
|
||||
This function will enable/disable trigger(s) on the table object
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
scid: Schema ID
|
||||
tid: Table ID
|
||||
"""
|
||||
# Below will decide if it's simple drop or drop with cascade call
|
||||
data = request.form if request.form else json.loads(
|
||||
request.data
|
||||
)
|
||||
# Convert str 'true' to boolean type
|
||||
is_enable_trigger = data['is_enable_trigger']
|
||||
|
||||
try:
|
||||
if foid is not None:
|
||||
status, data = self._fetch_properties(
|
||||
gid, sid, did, scid, foid, inherits=True)
|
||||
if not status:
|
||||
return data
|
||||
elif not data:
|
||||
return gone(self.not_found_error_msg())
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'enable_disable_trigger.sql']),
|
||||
data=data, is_enable_trigger=is_enable_trigger
|
||||
)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'get_enabled_triggers.sql']),
|
||||
tid=foid
|
||||
)
|
||||
|
||||
status, trigger_res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext("Trigger(s) have been disabled")
|
||||
if is_enable_trigger == 'D'
|
||||
else gettext("Trigger(s) have been enabled"),
|
||||
data={
|
||||
'id': foid,
|
||||
'scid': scid,
|
||||
'has_enable_triggers': trigger_res
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
def _get_resql_for_triggers(self, tid, schema,
|
||||
table):
|
||||
"""
|
||||
########################################
|
||||
# Reverse engineered sql for TRIGGERS
|
||||
########################################
|
||||
"""
|
||||
sql = render_template("/".join([self.trigger_template_path,
|
||||
self._NODES_SQL]), tid=tid)
|
||||
status, rset = self.conn.execute_2darray(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
trigger_sql = ''
|
||||
for row in rset['rows']:
|
||||
trigger_sql = trigger_utils.get_reverse_engineered_sql(
|
||||
self.conn, schema=schema, table=table, tid=tid,
|
||||
trid=row['oid'], datlastsysoid=self._DATABASE_LAST_SYSTEM_OID,
|
||||
show_system_objects=self.blueprint.show_system_objects,
|
||||
template_path=None)
|
||||
trigger_sql = "\n" + trigger_sql
|
||||
|
||||
trigger_sql = re.sub(self.pattern, self.double_newline,
|
||||
trigger_sql)
|
||||
return trigger_sql
|
||||
|
||||
|
||||
SchemaDiffRegistry(blueprint.node_type, ForeignTableView)
|
||||
ForeignTableView.register_node_view(blueprint)
|
||||
@@ -5,9 +5,10 @@ foreign tables.
|
||||
Do not remove these imports as they will be automatically imported by the view
|
||||
module as its children
|
||||
"""
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.columns \
|
||||
import blueprint as columns_module
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.triggers \
|
||||
import blueprint as triggers_modules
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||
constraints import blueprint as constraints_modules
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.\
|
||||
foreign_tables.foreign_table_columns import foreign_table_column_blueprint\
|
||||
as foreign_tables_columns_modules
|
||||
@@ -0,0 +1,97 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
""" Implements Column Node for foreign table """
|
||||
import pgadmin.browser.server_groups.servers.databases as database
|
||||
from flask_babel import gettext
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
|
||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.columns \
|
||||
import ColumnsView
|
||||
|
||||
|
||||
class ForeignTableColumnsModule(CollectionNodeModule):
|
||||
"""
|
||||
class ColumnsModule(CollectionNodeModule)
|
||||
|
||||
A module class for Column node derived from CollectionNodeModule.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
* __init__(*args, **kwargs)
|
||||
- Method is used to initialize the Column and it's base module.
|
||||
|
||||
* get_nodes(gid, sid, did, scid, tid)
|
||||
- Method is used to generate the browser collection node.
|
||||
|
||||
* node_inode()
|
||||
- Method is overridden from its base class to make the node as leaf node.
|
||||
|
||||
* script_load()
|
||||
- Load the module script for schema, when any of the server node is
|
||||
initialized.
|
||||
"""
|
||||
|
||||
_NODE_TYPE = 'foreign_table_column'
|
||||
_COLLECTION_LABEL = gettext("Columns")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Method is used to initialize the ColumnModule and it's base module.
|
||||
|
||||
Args:
|
||||
*args:
|
||||
**kwargs:
|
||||
"""
|
||||
self.min_ver = None
|
||||
self.max_ver = None
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_nodes(self, gid, sid, did, scid, foid, **kwargs):
|
||||
"""
|
||||
Generate the collection node
|
||||
"""
|
||||
if self.has_nodes(
|
||||
sid, did, scid=scid, tid=foid,
|
||||
base_template_path=ForeignTableColumnsView.BASE_TEMPLATE_PATH):
|
||||
yield self.generate_browser_collection_node(foid)
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
"""
|
||||
Load the module script for server, when any of the server-group node is
|
||||
initialized.
|
||||
"""
|
||||
return database.DatabaseModule.node_type
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
"""
|
||||
Load the module node as a leaf node
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def module_use_template_javascript(self):
|
||||
"""
|
||||
Returns whether Jinja2 template is used for generating the javascript
|
||||
module.
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
foreign_table_column_blueprint = ForeignTableColumnsModule(__name__)
|
||||
|
||||
|
||||
class ForeignTableColumnsView(ColumnsView):
|
||||
node_type = foreign_table_column_blueprint.node_type
|
||||
node_label = "Column"
|
||||
|
||||
|
||||
ForeignTableColumnsView.register_node_view(foreign_table_column_blueprint)
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#e1fff9;}.cls-2{fill:none;stroke:#aecec8;stroke-linejoin:round;stroke-width:0.75px;}.cls-3{fill:#16a085;}</style></defs><title>coll-column</title><g id="_2" data-name="2"><rect class="cls-1" x="4.15" y="1.95" width="5.5" height="9.9" rx="1" ry="1"/><line class="cls-2" x1="4.7" y1="6.9" x2="9.1" y2="6.9"/><line class="cls-2" x1="4.7" y1="9.1" x2="9.1" y2="9.1"/><path class="cls-3" d="M4.9,5.18l4,0v5.55a.35.35,0,0,1-.35.35H5.25a.35.35,0,0,1-.35-.35V5.18m-.75-.75v6.32a1.1,1.1,0,0,0,1.1,1.1h3.3a1.1,1.1,0,0,0,1.1-1.1V4.46l-5.5,0Z"/><path class="cls-3" d="M8.55,2.7A.35.35,0,0,1,8.9,3V4.5h-4V3a.35.35,0,0,1,.35-.35h3.3m0-.75H5.25A1.1,1.1,0,0,0,4.15,3v2.2h5.5V3A1.1,1.1,0,0,0,8.55,2Z"/><rect class="cls-1" x="6.35" y="4.15" width="5.5" height="9.9" rx="1" ry="1"/><line class="cls-2" x1="6.9" y1="9.1" x2="11.3" y2="9.1"/><line class="cls-2" x1="6.9" y1="11.3" x2="11.3" y2="11.3"/><path class="cls-3" d="M7.1,7.38l4,0V13a.35.35,0,0,1-.35.35H7.45A.35.35,0,0,1,7.1,13V7.38m-.75-.75V13A1.1,1.1,0,0,0,7.45,14h3.3a1.1,1.1,0,0,0,1.1-1.1V6.66l-5.5,0Z"/><path class="cls-3" d="M10.75,4.9a.35.35,0,0,1,.35.35V6.7h-4V5.25a.35.35,0,0,1,.35-.35h3.3m0-.75H7.45a1.1,1.1,0,0,0-1.1,1.1v2.2h5.5V5.25a1.1,1.1,0,0,0-1.1-1.1Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20"><defs><style>.cls-1{fill:#e1fff9;}.cls-2{fill:none;stroke:#aecec8;stroke-linejoin:round;stroke-width:0.75px;}.cls-3{fill:#16a085;}</style></defs><title>column</title><g id="_2" data-name="2"><rect class="cls-1" x="5.3" y="2.15" width="5.4" height="11.7" rx="1" ry="1"/><line class="cls-2" x1="5.75" y1="8" x2="10.25" y2="8"/><line class="cls-2" x1="5.75" y1="10.7" x2="10.25" y2="10.7"/><path class="cls-3" d="M6,5.83l3.9,0V13a.15.15,0,0,1-.15.15H6.2A.15.15,0,0,1,6,13V5.83M5.3,5.08V13a.9.9,0,0,0,.9.9H9.8a.9.9,0,0,0,.9-.9V5.1l-5.4,0Z"/><path class="cls-3" d="M9.8,2.9A.15.15,0,0,1,10,3V5H6V3A.15.15,0,0,1,6.2,2.9H9.8m0-.75H6.2a.9.9,0,0,0-.9.9v2.7h5.4V3a.9.9,0,0,0-.9-.9Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 768 B |
@@ -0,0 +1,70 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { getNodeColumnSchema } from '../../../static/js/foreign_table.ui';
|
||||
|
||||
define('pgadmin.node.foreign_table_column', [
|
||||
'sources/gettext', 'sources/url_for', 'pgadmin.browser',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, pgBrowser
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-foreign_table_column']) {
|
||||
pgBrowser.Nodes['coll-foreign_table_column'] =
|
||||
pgBrowser.Collection.extend({
|
||||
node: 'foreign_table_column',
|
||||
label: gettext('Columns'),
|
||||
type: 'coll-foreign_table_column',
|
||||
columns: ['name', 'cltype', 'description']
|
||||
});
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['foreign_table_column']) {
|
||||
pgBrowser.Nodes['foreign_table_column'] = pgBrowser.Node.extend({
|
||||
// Foreign table is added in parent_type to support triggers on
|
||||
// foreign table where we need column information.
|
||||
parent_type: ['foreign_table'],
|
||||
collection_type: ['coll-foreign_table'],
|
||||
type: 'foreign_table_column',
|
||||
label: gettext('Column'),
|
||||
hasSQL: true,
|
||||
sqlAlterHelp: 'sql-altertable.html',
|
||||
sqlCreateHelp: 'sql-altertable.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'column_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: false,
|
||||
hasDepends: true,
|
||||
hasStatistics: true,
|
||||
Init: function() {
|
||||
/* Avoid multiple registration of menus */
|
||||
if (this.initialized)
|
||||
return;
|
||||
|
||||
this.initialized = true;
|
||||
pgBrowser.add_menus([{
|
||||
name: 'create_column_on_coll', node: 'coll-foreign_table_column', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Column...'),
|
||||
data: {action: 'create'}, enable: 'canCreate',
|
||||
},{
|
||||
name: 'create_column_onTable', node: 'foreign_table', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: gettext('Column...'),
|
||||
data: {action: 'create'}, enable: 'canCreate',
|
||||
},
|
||||
]);
|
||||
},
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return getNodeColumnSchema(treeNodeInfo, itemNodeData, pgBrowser);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['foreign_table_column'];
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
|
||||
class ForeignTableGeneratorTestCase(BaseTestGenerator):
|
||||
|
||||
def runTest(self):
|
||||
return []
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"column_create": [
|
||||
{
|
||||
"name": "Create: Add FT column with valid data",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"name": "test_ft_column_add_",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"coloptions":[],
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create: Add FT column with valid data while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"name": "test_column_add_",
|
||||
"cltype": "\"char\"",
|
||||
"attacl": [],
|
||||
"is_primary_key": false,
|
||||
"attnotnull": false,
|
||||
"attlen": null,
|
||||
"attprecision": null,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"description": {
|
||||
"comment": "jsoncomment"
|
||||
}
|
||||
},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_scalar",
|
||||
"return_value": "[(False, 'Mocked Internal Server Error'),(True,True)]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"column_delete": [
|
||||
{
|
||||
"name": "Delete: Existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Delete: Multiple existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": true
|
||||
},
|
||||
{
|
||||
"name": "Delete: Non-existing FT column",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {
|
||||
"column_id": 9999999
|
||||
},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": "Error: Object not found.",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Delete: Existing FT column while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict",
|
||||
"return_value": "[(False,'Mocked Internal Server Error')]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
}
|
||||
],
|
||||
"column_get": [
|
||||
{
|
||||
"name": "Get details: For existing FT column",
|
||||
"is_positive_test": true,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": false,
|
||||
"mock_data": {},
|
||||
"expected_data": {
|
||||
"status_code": 200,
|
||||
"error_msg": null,
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
},
|
||||
{
|
||||
"name": "Get details: For existing FT column while server down",
|
||||
"is_positive_test": false,
|
||||
"inventory_data": {},
|
||||
"test_data": {},
|
||||
"mocking_required": true,
|
||||
"mock_data": {
|
||||
"function_name": "pgadmin.utils.driver.psycopg3.connection.Connection.execute_dict",
|
||||
"return_value": "[(False,'Mocked Internal Server Error')]"
|
||||
},
|
||||
"expected_data": {
|
||||
"status_code": 500,
|
||||
"error_msg": "Mocked Internal Server Error",
|
||||
"test_result_data": {}
|
||||
},
|
||||
"is_list": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" TYPE time(10) with time zone ;
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" DROP NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time(6) with time zone DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#" OPTIONS (SET column_name 'test_options_update');
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options_update') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,9 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS (1000+1) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
||||
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FDW for foreign table",
|
||||
"endpoint": "NODE-foreign_data_wrapper.obj",
|
||||
"sql_endpoint": "NODE-foreign_data_wrapper.sql_id",
|
||||
"data": {
|
||||
"name": "test_fdw_for_foreign_table_columns",
|
||||
"fdwacl": [],
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
"sql_endpoint": "NODE-foreign_server.sql_id",
|
||||
"data": {
|
||||
"name":"test_fs_for_foreign_table_column"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table for testing column node.",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
"sql_endpoint": "NODE-foreign_table.sql_id",
|
||||
"data": {
|
||||
"name": "foreign_table_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"columns": [],
|
||||
"schema": "public",
|
||||
"basensp": "public",
|
||||
"ftsrvname": "test_fs_for_foreign_table_column",
|
||||
"owner": "postgres",
|
||||
"ftoptions": [],
|
||||
"inherits": [],
|
||||
"relacl": [],
|
||||
"seclabels": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"expected_sql_file": "create_column_numeric.sql",
|
||||
"expected_msql_file": "create_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 1,
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for alter",
|
||||
"cltype": "real",
|
||||
"coloptions":{"added":[{"option":"column_name","value":"test"}]}
|
||||
},
|
||||
"expected_sql_file": "alter_column_numeric.sql",
|
||||
"expected_msql_file": "alter_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with text & default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "text",
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "'xyz'"
|
||||
},
|
||||
"expected_sql_file": "create_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "create_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 2,
|
||||
"defval": "'changed default value'"
|
||||
},
|
||||
"expected_sql_file": "alter_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "alter_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with time with time zone & default value using function",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "time with time zone",
|
||||
"attacl": [],
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "now()"
|
||||
},
|
||||
"expected_sql_file": "create_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "create_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with time with time zone & update length",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attlen": "10",
|
||||
"attnotnull": false,
|
||||
"attnum":3,
|
||||
"description": "test comment modification"
|
||||
},
|
||||
"expected_sql_file": "alter_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "alter_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {"name":"col_4_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description":"test comment",
|
||||
"cltype":"bigint",
|
||||
"attnotnull":true,
|
||||
"coloptions":[{"option":"column_name","value":"test_options"}],
|
||||
"colconstype":"g",
|
||||
"is_tlength":false,
|
||||
"is_precision":false,
|
||||
"genexpr":"1000+1",
|
||||
"attoptions":[{"name":"n_distinct","value":"1"}]},
|
||||
"expected_sql_file": "create_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "create_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data":{
|
||||
"attoptions":{
|
||||
"changed":[{"name":"n_distinct","value":"111"}]},
|
||||
"coloptions":{"changed":[{"option":"column_name","value":"test_options_update"}]},
|
||||
"attnum":4},
|
||||
"expected_sql_file": "alter_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "alter_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_columnn.sql_id",
|
||||
"data": {
|
||||
"name":"col_4_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]}
|
||||
@@ -0,0 +1,10 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
RENAME "col_1_$%{}[]()&*^!@""'`\/#" TO "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" OPTIONS (ADD column_name 'test');
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" TYPE real;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" real OPTIONS (column_name 'test') NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_2_$%{}[]()&*^!@""'`\/#" SET DEFAULT 'changed default value';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_2_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text COLLATE pg_catalog."default" NOT NULL DEFAULT 'changed default value'::text;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_1_$%{}[]()&*^!@""'`\/#" numeric(10, 5) NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for create';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_1_$%{}[]()&*^!@""'`\/#" numeric(10,5) NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for create';
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text NOT NULL DEFAULT 'xyz';
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_2_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_2_$%{}[]()&*^!@""'`\/#" text COLLATE pg_catalog."default" NOT NULL DEFAULT 'xyz'::text;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_2_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FDW for foreign table",
|
||||
"endpoint": "NODE-foreign_data_wrapper.obj",
|
||||
"sql_endpoint": "NODE-foreign_data_wrapper.sql_id",
|
||||
"data": {
|
||||
"name": "test_fdw_for_foreign_table_columns",
|
||||
"fdwacl": [],
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
"sql_endpoint": "NODE-foreign_server.sql_id",
|
||||
"data": {
|
||||
"name":"test_fs_for_foreign_table_column"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table for testing column node.",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
"sql_endpoint": "NODE-foreign_table.sql_id",
|
||||
"data": {
|
||||
"name": "foreign_table_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"columns": [],
|
||||
"schema": "public",
|
||||
"basensp": "public",
|
||||
"ftsrvname": "test_fs_for_foreign_table_column",
|
||||
"owner": "postgres",
|
||||
"ftoptions": [],
|
||||
"inherits": [],
|
||||
"relacl": [],
|
||||
"seclabels": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"coloptions":[],
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"expected_sql_file": "create_column_numeric.sql",
|
||||
"expected_msql_file": "create_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 1,
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for alter",
|
||||
"cltype": "real",
|
||||
"coloptions":{"added":[{"option":"column_name","value":"test"}]}
|
||||
},
|
||||
"expected_sql_file": "alter_column_numeric.sql",
|
||||
"expected_msql_file": "alter_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with text & default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "text",
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "'xyz'"
|
||||
},
|
||||
"expected_sql_file": "create_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "create_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 2,
|
||||
"defval": "'changed default value'"
|
||||
},
|
||||
"expected_sql_file": "alter_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "alter_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]}
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" TYPE time(10) with time zone ;
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_3_$%{}[]()&*^!@""'`\/#" DROP NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time(6) with time zone DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment modification';
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#" OPTIONS (SET column_name 'test_options_update');
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options_update') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=111);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_3_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_3_$%{}[]()&*^!@""'`\/#" time with time zone NOT NULL DEFAULT now();
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_3_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
@@ -0,0 +1,9 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS (1000+1) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "col_4_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "col_4_$%{}[]()&*^!@""'`\/#" bigint OPTIONS (column_name 'test_options') NOT NULL GENERATED ALWAYS AS ((1000 + 1)) STORED;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."col_4_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'test comment';
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "col_4_$%{}[]()&*^!@""'`\/#"
|
||||
SET (n_distinct=1);
|
||||
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"scenarios": [
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FDW for foreign table",
|
||||
"endpoint": "NODE-foreign_data_wrapper.obj",
|
||||
"sql_endpoint": "NODE-foreign_data_wrapper.sql_id",
|
||||
"data": {
|
||||
"name": "test_fdw_for_foreign_table_columns",
|
||||
"fdwacl": [],
|
||||
"fdwoptions": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create foreign server for foreign table",
|
||||
"endpoint": "NODE-foreign_server.obj",
|
||||
"sql_endpoint": "NODE-foreign_server.sql_id",
|
||||
"data": {
|
||||
"name":"test_fs_for_foreign_table_column"
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create Foreign Table for testing column node.",
|
||||
"endpoint": "NODE-foreign_table.obj",
|
||||
"sql_endpoint": "NODE-foreign_table.sql_id",
|
||||
"data": {
|
||||
"name": "foreign_table_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"columns": [],
|
||||
"schema": "public",
|
||||
"basensp": "public",
|
||||
"ftsrvname": "test_fs_for_foreign_table_column",
|
||||
"owner": "enterprisedb",
|
||||
"ftoptions": [],
|
||||
"inherits": [],
|
||||
"relacl": [],
|
||||
"seclabels": []
|
||||
},
|
||||
"store_object_id": "True"
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for create",
|
||||
"cltype": "numeric",
|
||||
"attlen":"10",
|
||||
"attprecision":"5",
|
||||
"colconstype":"n",
|
||||
"attnotnull": true,
|
||||
"attoptions": [],
|
||||
"seclabels": [],
|
||||
"defval": "1"
|
||||
},
|
||||
"expected_sql_file": "create_column_numeric.sql",
|
||||
"expected_msql_file": "create_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 1,
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description": "Comment for alter",
|
||||
"cltype": "real",
|
||||
"coloptions":{"added":[{"option":"column_name","value":"test"}]}
|
||||
},
|
||||
"expected_sql_file": "alter_column_numeric.sql",
|
||||
"expected_msql_file": "alter_column_numeric.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column (Integer/Numeric type)",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "new_col_1_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with text & default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "text",
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "'xyz'"
|
||||
},
|
||||
"expected_sql_file": "create_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "create_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attnum": 2,
|
||||
"defval": "'changed default value'"
|
||||
},
|
||||
"expected_sql_file": "alter_column_text_with_default_value.sql",
|
||||
"expected_msql_file": "alter_column_text_with_default_value.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT column with text & update default value",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_2_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with time with time zone & default value using function",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/#",
|
||||
"cltype": "time with time zone",
|
||||
"attacl": [],
|
||||
"description": "test comment",
|
||||
"attnotnull": true,
|
||||
"colconstype": "n",
|
||||
"defval": "now()"
|
||||
},
|
||||
"expected_sql_file": "create_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "create_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with time with time zone & update length",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data": {
|
||||
"attlen": "10",
|
||||
"attnotnull": false,
|
||||
"attnum":3,
|
||||
"description": "test comment modification"
|
||||
},
|
||||
"expected_sql_file": "alter_column_timestamp_with_default_value_using_function.sql",
|
||||
"expected_msql_file": "alter_column_timestamp_with_default_value_using_function.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"data": {
|
||||
"name": "col_3_$%{}[]()&*^!@\"'`\\/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "create",
|
||||
"name": "Create FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql",
|
||||
"data": {"name":"col_4_$%{}[]()&*^!@\"'`\\/#",
|
||||
"description":"test comment",
|
||||
"cltype":"bigint",
|
||||
"attnotnull":true,
|
||||
"coloptions":[{"option":"column_name","value":"test_options"}],
|
||||
"colconstype":"g",
|
||||
"is_tlength":false,
|
||||
"is_precision":false,
|
||||
"genexpr":"1000+1",
|
||||
"attoptions":[{"name":"n_distinct","value":"1"}]},
|
||||
"expected_sql_file": "create_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "create_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "alter",
|
||||
"name": "Alter FT Column with integer & generated always with expression, column option, variables",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_column.sql_id",
|
||||
"msql_endpoint": "NODE-foreign_table_column.msql_id",
|
||||
"data":{
|
||||
"attoptions":{
|
||||
"changed":[{"name":"n_distinct","value":"111"}]},
|
||||
"coloptions":{"changed":[{"option":"column_name","value":"test_options_update"}]},
|
||||
"attnum":4},
|
||||
"expected_sql_file": "alter_column_with_integer_generated_always_column_option_variables.sql",
|
||||
"expected_msql_file": "alter_column_with_integer_generated_always_column_option_variables.msql"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"name": "Drop FT Column with time with time zone",
|
||||
"endpoint": "NODE-foreign_table_column.obj_id",
|
||||
"sql_endpoint": "NODE-foreign_table_columnn.sql_id",
|
||||
"data": {
|
||||
"name":"col_4_$%{}[]()&*^!@\"'`\\/#"
|
||||
}
|
||||
}
|
||||
]}
|
||||
@@ -0,0 +1,10 @@
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
RENAME "col_1_$%{}[]()&*^!@""'`\/#" TO "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" OPTIONS (ADD column_name 'test');
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ALTER COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" TYPE real;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Column: public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
|
||||
-- ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#" DROP COLUMN IF EXISTS "new_col_1_$%{}[]()&*^!@""'`\/#";
|
||||
|
||||
ALTER FOREIGN TABLE IF EXISTS public."foreign_table_2_$%{}[]()&*^!@""'`\/#"
|
||||
ADD COLUMN "new_col_1_$%{}[]()&*^!@""'`\/#" real OPTIONS (column_name 'test') NOT NULL DEFAULT 1;
|
||||
|
||||
COMMENT ON COLUMN public."foreign_table_2_$%{}[]()&*^!@""'`\/#"."new_col_1_$%{}[]()&*^!@""'`\/#"
|
||||
IS 'Comment for alter';
|
||||