Compare commits

...
42 Commits
Author SHA1 Message Date
Akshay Joshi 173acd46a5 Update version for release 2019-06-25 01:44:21 +05:30
Aditya Toshniwal c39d257bf6 Fix an XSS issue when username contains XSS vulnerable text. Fixes #4386 2019-06-24 16:06:03 +05:30
Identifier Anonymous b3490ba3de Update Japanese translation 2019-06-24 05:52:53 +05:30
Fred Escallier 4e5d8fe8e2 Update French translation 2019-06-21 16:46:13 +05:30
Akshay Joshi c4de5474a4 Update message catalogs 2019-06-21 15:59:14 +05:30
Aditya Toshniwal ebb5e3fe65 Ensure Python escaping matched JS escaping and fix a minor XSS issue in the Query Tool that required superuser access to trigger. Fixes #4378 2019-06-21 09:53:57 +01:00
Dave Page 644624eabe PEP-8 fixes. 2019-06-20 14:30:31 +01:00
Dave Page 9dbb74367d Fix regression tests. 2019-06-20 14:02:15 +01:00
Khushboo Vashi c07e52b9de Ensure that both columns and partitions can be edited at the same time in the table dialog. Fixes #4380 2019-06-20 13:37:36 +01:00
Aditya Toshniwal 78d55c7cc0 Fix regression tests. 2019-06-20 13:26:06 +01:00
Dave Page 81752bb998 Remove additional "SETOF" included when generating CREATE scripts for trigger functions. Fixes #4362 2019-06-20 13:18:30 +01:00
Dave Page fb4afce629 Fix formatting change which inadvertently broke the feature tests. 2019-06-20 12:43:07 +01:00
Aditya Toshniwal 6e8ebbd375 Allow editing of data where a primary key column includes a % sign in the value. Fixes #4036
Fix an XSS issue seen in View/Edit data mode if a column name includes HTML. Fixes #4367
2019-06-20 12:21:37 +01:00
Akshay Joshi 5c0ea0c012 Capitalize the word 'export' used in Import/Export module. Fixes #4345 2019-06-19 16:17:29 +05:30
Aditya Toshniwal ce7679c4bd Added missing __init__.py file in debugger utils which is required for Python 2.7 2019-06-19 13:31:48 +05:30
Akshay Joshi b36d5d153b Ensure the debugger control buttons are only enabled once initialisation is complete. Fixes #4360 2019-06-18 14:46:28 +01:00
Akshay Joshi 9e65c971a3 Add a framework for testing reversed engineered SQL and CRUD API endpoints. Fixes #4202 2019-06-18 14:28:25 +01:00
Dave Page 71919a4ce9 Prevent the "Please login to access this page" message displaying multiple times. Fixes #4306 2019-06-17 14:12:36 +01:00
Aditya Toshniwal 402dfd07db Change icons for table inheritance (icons by Chethana Kumar) Fixes #3174
Along with this, I have also fixed few other issues/icons found on the way:
1) Dependencies tab for inherited tables/foreign keys shows partial text (Fixes ##3994).
2) Dependencies tab for child partition table shows parent partition table as Function.
3) Dependencies tab for triggers shows trigger functions as plain functions.
4) Dependents tab for partitioned table shows the child partition tables as normal table instead for partitioned tables.
2019-06-17 10:36:30 +01:00
Akshay Joshi bf548dda3f Fix help links for backup globals and backup server. Fixes #4365 2019-06-17 13:27:21 +05:30
Aditya Toshniwal 2894c6cd14 Add minor change missed in previous commit. Fixes #4329 2019-06-14 12:46:48 +01:00
Aditya Toshniwal 3b69f92d70 Ensure strings are properly encoded in the Query History. Fixes #4349 2019-06-14 09:17:02 +01:00
Aditya Toshniwal 82bd94e696 Fix connection restoration issue when pgAdmin server is restarted and the page is refreshed. Fixes #4357 2019-06-14 11:50:01 +05:30
Akshay Joshi 04328b76ba Fix syntax error for Default value of column. It is a regression of #4253 2019-06-13 18:04:43 +05:30
Murtuza Zabuawala 08b78fb6a1 Ensure we include the CSRF token when uploading files. Fixes #4350 2019-06-12 13:52:18 +01:00
Aditya Toshniwal 23364464c2 Ensure the correct label is used in panel headers when viewing filtered rows. Fixes #4228 2019-06-11 15:11:23 +01:00
Akshay Joshi d774a0ff67 Fix issue where property dialog of column should open properly for EPAS v12. Fixes #4343 2019-06-11 17:48:01 +05:30
Aditya Toshniwal 5437a8adab Fix an initialisation error when two functions with parameters are debugged in parallel. Fixes #4329 2019-06-10 14:58:07 +01:00
Dave Page 6d52f2b911 Initial support for PostgreSQL 12. Fixes #4283. Fixes #4288. Fixes #4290. 2019-06-10 14:24:45 +01:00
Dave Page 2ca11c84e8 Ensure that the Return key can be used to submit the Master Password dialogue. Fixes #4310
Ensure that browser auto-fill doesn't cause Help pages to be opened unexpectedly. Fixes #4317
2019-06-10 14:03:56 +01:00
Aditya Toshniwal f561c0cee6 Fix keyboard navigation in "inner" tabsets such as the Query Tool and Debugger. Fixes #4195 2019-06-10 11:10:49 +01:00
Fred Escallier 321b445a7e Update French translation. 2019-06-10 10:08:27 +01:00
Aditya Toshniwal 7ff85903e4 Fix issue where reverse engineered SQL was failing for foreign tables, if it had = in the options. Fixes #4171 2019-06-10 12:15:12 +05:30
Aditya Toshniwal 8b9c50ee5c Fix issue where new column should be created with Default value. Fixes #4235 2019-06-10 11:53:16 +05:30
Ma Yanhong 4b6e9b031c Update Chinese translation. 2019-06-06 10:06:28 +01:00
Dave Page e691885881 Clarify warnings about disabling the master password. 2019-06-05 15:32:47 +01:00
Dave Page caf181d5e3 Clarify docs around configuration files and disabling the master password. 2019-06-05 15:20:38 +01:00
Aditya Toshniwal d90136d93d Prevent the geometry viewer grabbing key presses when not in focus under Firefox, IE and Edge. Fixes #4255 2019-06-05 12:00:09 +01:00
Aditya Toshniwal 9a00a8a60b Update codemirror version. Fixes #4035 2019-06-05 12:12:56 +05:30
Aditya Toshniwal a588c2994d 1) Fix issue where SSH tunnel connection using password is failing, it's regression of Master Password. Fixes #4320
2) Fix some more issues related to SSH Tunnel(By: Akshay Joshi)
2019-06-05 12:07:24 +05:30
Dave Page 13704a4f34 Disable upgrade checks whilst testing. 2019-06-03 11:35:59 -04:00
Usman Muzaffar 912db8913f Ensure that successful maintenance tasks don't leave a notifier window behind when running regression tests. 2019-06-03 11:33:32 -04:00
153 changed files with 10032 additions and 9211 deletions

No files matched your search

+3
View File
@@ -43,6 +43,9 @@ check-pep8:
check-python:
cd web && python regression/runtests.py --exclude feature_tests
check-resql:
cd web && python regression/runtests.py --pkg resql --exclude feature_tests
check-feature: install-node bundle
cd web && python regression/runtests.py --pkg feature_tests
+6 -2
View File
@@ -45,11 +45,15 @@ are as follows:
* ``config_distro.py``: This file is read after ``config.py`` and is intended for
packagers to change any settings that are required for their pgAdmin distribution.
This may typically include certain paths and file locations.
This may typically include certain paths and file locations. This file is optional,
and may be created by packagers in the same directory as ``config.py`` if
needed.
* ``config_local.py``: This file is read after ``config_distro.py`` and is intended
for end users to change any default or packaging specific settings that they may
wish to adjust to meet local preferences or standards.
wish to adjust to meet local preferences or standards.This file is optional,
and may be created by users in the same directory as ``config.py`` if
needed.
.. note:: If the SERVER_MODE setting is changed in ``config_distro.py`` or ``config_local.py``,
you will most likely need to re-set the LOG_FILE, SQLITE_PATH, SESSION_DB_PATH
+11 -9
View File
@@ -193,8 +193,8 @@ When using the Debugger, the following shortcuts are available:
| Alt + Shift + q | Option + Shift + q | Enter or Edit values in Grid |
+--------------------------+--------------------+-----------------------------------+
Inner Panel Navigation
**********************
Inner Tab and Panel Navigation
******************************
When using the Query Tool and Debugger, the following shortcuts are available
for inner panel navigation:
@@ -203,13 +203,15 @@ for inner panel navigation:
:class: longtable
:widths: 2 2 3
+--------------------------+---------------------+------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+=====================+==============================+
| Alt + Shift + Right | Alt + Shift + Right | Move to next inner panel |
+--------------------------+---------------------+------------------------------+
| Alt + Shift + Left | Alt + Shift + Left | Move to previous inner panel |
+--------------------------+---------------------+------------------------------+
+--------------------------+---------------------------+------------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+===========================+====================================+
| Alt + Shift + ] | Alt + Shift + ] | Move to next tab within a panel |
+--------------------------+---------------------------+------------------------------------+
| Alt + Shift + [ | Alt + Shift + [ | Move to previous tab within a panel|
+--------------------------+---------------------------+------------------------------------+
| Alt + Shift + Tab | Alt + Shift + Tab | Move between inner panels |
+--------------------------+---------------------------+------------------------------------+
Access Key
**********
+32 -13
View File
@@ -4,35 +4,54 @@
`Master Password`:index:
************************
A master password is required to secure and later unlock the saved server passwords. This is applicable only for desktop mode users.
A master password is required to secure and later unlock the saved server
passwords. This is applicable only for desktop mode users.
* You are prompted to enter the master password when you open the window for the first time after starting the application.
* Once you set the master password, all the existing saved passwords will be re-encrypted using the master password.
* The server passwords which are saved in the SQLite DB file are encrypted and decrypted using the master password.
* You are prompted to enter the master password when you open the window for
the first time after starting the application.
* Once you set the master password, all the existing saved passwords will be
re-encrypted using the master password.
* The server passwords which are saved in the SQLite DB file are encrypted and
decrypted using the master password.
.. image:: images/master_password_set.png
:alt: Set master password
:align: center
* You can disable the master password by setting the configuration parameter *MASTER_PASSWORD_REQUIRED=False*
* Note that, if master password is disabled, then all the saved passwords will be removed.
* You can disable the master password by setting the configuration parameter
*MASTER_PASSWORD_REQUIRED=False*. See :ref:`Desktop Deployment <desktop_deployment>`
for more information.
.. warning:: If master password is disabled, then the saved passwords will be encrypted using a key
which may not be as secure as master password. It is strongly recommended to use master password if you use "Save password" option.
.. note:: If the master password is disabled, then all the saved passwords will
be removed.
* The master password is not stored anywhere on the physical storage. It is temporarily stored in the application memory and it does not get saved in case the application gets restarted.
* You are prompted to enter the master password when pgAdmin server is restarted.
.. warning:: If the master password is disabled, then the saved passwords will
be encrypted using a key which is derived from information within the
configuration database. Use of a master password ensures that the encryption
key does not need to be stored anywhere, and thus prevents possible access
to server credentials if the configuration database becomes available to an
attacker.
It is **strongly** recommended that you use the master password if you use
the *Save Password* option.
* The master password is not stored anywhere on the physical storage. It is
temporarily stored in the application memory and it does not get saved when
the application is restarted.
* You are prompted to enter the master password when pgAdmin server is
restarted.
.. image:: images/master_password_enter.png
:alt: Enter master password
:align: center
* If you forget the master password, you can use the "Reset Master Password" button to reset the password.
* If you forget the master password, you can use the *Reset Master Password*
button to reset the password.
.. image:: images/master_password_reset.png
:alt: Reset master password
:align: center
.. warning:: Resetting the master password will also remove all the saved passwords and close all the existing established
connections.
.. warning:: Resetting the master password will also remove all saved passwords
and close all existing established connections.
+1
View File
@@ -11,6 +11,7 @@ notes for it.
.. toctree::
:maxdepth: 1
release_notes_4_9
release_notes_4_8
release_notes_4_7
release_notes_4_6
+44
View File
@@ -0,0 +1,44 @@
***********
Version 4.9
***********
Release date: 2019-06-27
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.8.
New features
************
| `Feature #3174 <https://redmine.postgresql.org/issues/3174>`_ - Visually distinguish simple tables from tables that are inherited and from which other tables are inherited.
| `Feature #4202 <https://redmine.postgresql.org/issues/4202>`_ - Add a framework for testing reversed engineered SQL and CRUD API endpoints.
Bug fixes
*********
| `Bug #3994 <https://redmine.postgresql.org/issues/3994>`_ - Fix issue where the dependencies tab for inherited tables/foreign keys shows partial text.
| `Bug #4036 <https://redmine.postgresql.org/issues/4036>`_ - Allow editing of data where a primary key column includes a % sign in the value.
| `Bug #4171 <https://redmine.postgresql.org/issues/4171>`_ - Fix issue where reverse engineered SQL was failing for foreign tables, if it had "=" in the options.
| `Bug #4195 <https://redmine.postgresql.org/issues/4195>`_ - Fix keyboard navigation in "inner" tabsets such as the Query Tool and Debugger.
| `Bug #4228 <https://redmine.postgresql.org/issues/4228>`_ - Ensure the correct label is used in panel headers when viewing filtered rows.
| `Bug #4253 <https://redmine.postgresql.org/issues/4253>`_ - Fix issue where new column should be created with Default value.
| `Bug #4283 <https://redmine.postgresql.org/issues/4283>`_ - Initial support for PostgreSQL 12.
| `Bug #4288 <https://redmine.postgresql.org/issues/4288>`_ - Initial support for PostgreSQL 12.
| `Bug #4290 <https://redmine.postgresql.org/issues/4290>`_ - Initial support for PostgreSQL 12.
| `Bug #4255 <https://redmine.postgresql.org/issues/4255>`_ - Prevent the geometry viewer grabbing key presses when not in focus under Firefox, IE and Edge.
| `Bug #4306 <https://redmine.postgresql.org/issues/4306>`_ - Prevent the "Please login to access this page" message displaying multiple times.
| `Bug #4310 <https://redmine.postgresql.org/issues/4310>`_ - Ensure that the Return key can be used to submit the Master Password dialogue.
| `Bug #4317 <https://redmine.postgresql.org/issues/4317>`_ - Ensure that browser auto-fill doesn't cause Help pages to be opened unexpectedly.
| `Bug #4320 <https://redmine.postgresql.org/issues/4320>`_ - Fix issue where SSH tunnel connection using password is failing, it's regression of Master Password.
| `Bug #4329 <https://redmine.postgresql.org/issues/4329>`_ - Fix an initialisation error when two functions with parameters are debugged in parallel.
| `Bug #4343 <https://redmine.postgresql.org/issues/4343>`_ - Fix issue where property dialog of column should open properly for EPAS v12.
| `Bug #4345 <https://redmine.postgresql.org/issues/4345>`_ - Capitalize the word 'export' used in Import/Export module.
| `Bug #4349 <https://redmine.postgresql.org/issues/4349>`_ - Ensure strings are properly encoded in the Query History.
| `Bug #4350 <https://redmine.postgresql.org/issues/4350>`_ - Ensure we include the CSRF token when uploading files.
| `Bug #4357 <https://redmine.postgresql.org/issues/4357>`_ - Fix connection restoration issue when pgAdmin server is restarted and the page is refreshed.
| `Bug #4360 <https://redmine.postgresql.org/issues/4360>`_ - Ensure the debugger control buttons are only enabled once initialisation is complete.
| `Bug #4362 <https://redmine.postgresql.org/issues/4362>`_ - Remove additional "SETOF" included when generating CREATE scripts for trigger functions.
| `Bug #4365 <https://redmine.postgresql.org/issues/4365>`_ - Fix help links for backup globals and backup server.
| `Bug #4367 <https://redmine.postgresql.org/issues/4367>`_ - Fix an XSS issue seen in View/Edit data mode if a column name includes HTML.
| `Bug #4378 <https://redmine.postgresql.org/issues/4378>`_ - Ensure Python escaping matched JS escaping and fix a minor XSS issue in the Query Tool that required superuser access to trigger.
| `Bug #4380 <https://redmine.postgresql.org/issues/4380>`_ - Ensure that both columns and partitions can be edited at the same time in the table dialog.
| `Bug #4386 <https://redmine.postgresql.org/issues/4386>`_ - Fix an XSS issue when username contains XSS vulnerable text.
+6 -2
View File
@@ -68,11 +68,15 @@ pgAdmin. These are as follows:
* ``config_distro.py``: This file is read after ``config.py`` and is intended for
packagers to change any settings that are required for their pgAdmin distribution.
This may typically include certain paths and file locations.
This may typically include certain paths and file locations. This file is optional,
and may be created by packagers in the same directory as ``config.py`` if
needed.
* ``config_local.py``: This file is read after ``config_distro.py`` and is intended
for end users to change any default or packaging specific settings that they may
wish to adjust to meet local preferences or standards.
wish to adjust to meet local preferences or standards. This file is optional,
and may be created by administrators in the same directory as ``config.py`` if
needed.
Python
------
+2 -2
View File
@@ -8,9 +8,9 @@
<key>CFBundleName</key>
<string>pgAdmin 4</string>
<key>CFBundleShortVersionString</key>
<string>4.8.0</string>
<string>4.9.0</string>
<key>CFBundleVersion</key>
<string>4.8.0</string>
<string>4.9.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
<key>NSHumanReadableCopyright</key>
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = 4.8.0.0
VERSION = 4.9.0.0
QMAKE_TARGET_COMPANY = "The pgAdmin Development Team"
QMAKE_TARGET_PRODUCT = "pgAdmin 4"
QMAKE_TARGET_DESCRIPTION = "pgAdmin 4 Desktop Runtime"
+2 -2
View File
@@ -50,7 +50,7 @@ APP_ICON = 'pg-icon'
# Application version number components
APP_RELEASE = 4
APP_REVISION = 8
APP_REVISION = 9
# 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 = 40800
APP_VERSION_INT = 40900
# DO NOT CHANGE!
# The application version string, constructed from the components
+2 -2
View File
@@ -56,7 +56,7 @@
"bootstrap4-toggle": "3.4.0",
"bowser": "2.1.2",
"browserify": "~16.2.3",
"codemirror": "^5.44.0",
"codemirror": "^5.47.0",
"css-loader": "2.1.0",
"cssnano": "^4.1.10",
"dropzone": "^5.5.1",
@@ -71,7 +71,7 @@
"jquery-contextmenu": "^2.8.0",
"jquery-ui": "^1.12.1",
"json-bignumber": "^1.0.1",
"leaflet": "^1.4.0",
"leaflet": "^1.5.1",
"moment": "^2.24.0",
"moment-timezone": "^0.5.23",
"mousetrap": "^1.6.3",
+6 -2
View File
@@ -237,6 +237,7 @@ def create_app(app_name=None):
):
config.SQLITE_PATH = config.TEST_SQLITE_PATH
config.MASTER_PASSWORD_REQUIRED = False
config.UPGRADE_CHECK_ENABLED = False
# Ensure the various working directories exist
from pgadmin.setup import create_app_data_directory, db_upgrade
@@ -645,8 +646,11 @@ def create_app(app_name=None):
# if the server is restarted the in memory key will be lost
# but the user session may still be active. Logout the user
# to get the key again when login
if config.SERVER_MODE and current_app.keyManager.get() is None:
logout_user()
if config.SERVER_MODE and current_user.is_authenticated:
if current_app.keyManager.get() is None and \
request.endpoint not in ('security.login',
'security.logout'):
logout_user()
@app.after_request
def after_request(response):
@@ -0,0 +1,9 @@
-- Cast: money -> bigint
-- DROP CAST (money AS bigint);
CREATE CAST (money AS bigint)
WITHOUT FUNCTION
AS IMPLICIT;
COMMENT ON CAST (money AS bigint) IS 'Cast from money to bigint';
@@ -0,0 +1,7 @@
-- Cast: money -> bigint
-- DROP CAST (money AS bigint);
CREATE CAST (money AS bigint)
WITHOUT FUNCTION
AS IMPLICIT;
@@ -0,0 +1,68 @@
{
"scenarios": [
{
"type": "create",
"name": "Create IMPLICIT Cast",
"endpoint": "NODE-cast.obj",
"sql_endpoint": "NODE-cast.sql_id",
"data": {
"castcontext": "IMPLICIT",
"encoding": "UTF8",
"name": "money->bigint",
"srctyp": "money",
"trgtyp": "bigint"
},
"expected_sql_file": "create_implicit_cast.sql"
},
{
"type": "alter",
"name": "Alter IMPLICIT Cast",
"endpoint": "NODE-cast.obj_id",
"sql_endpoint": "NODE-cast.sql_id",
"data": {
"description": "Cast from money to bigint"
},
"expected_sql_file": "alter_implicit_cast.sql"
},
{
"type": "delete",
"name": "Drop IMPLICIT Cast",
"endpoint": "NODE-cast.delete_id",
"data": {
"name": "money->bigint"
}
},
{
"type": "create",
"name":"Create EXPLICIT Cast",
"endpoint": "NODE-cast.obj",
"sql_endpoint": "NODE-cast.sql_id",
"data": {
"castcontext": "EXPLICIT",
"encoding": "UTF8",
"name": "money->bigint",
"srctyp": "money",
"trgtyp": "bigint"
},
"expected_sql": "-- Cast: money -> bigint\n\n-- DROP CAST (money AS bigint);\n\nCREATE CAST (money AS bigint)\n\tWITHOUT FUNCTION;"
},
{
"type": "alter",
"name": "Alter EXPLICIT Cast",
"endpoint": "NODE-cast.obj_id",
"sql_endpoint": "NODE-cast.sql_id",
"data": {
"description": "Cast from money to bigint"
},
"expected_sql": "-- Cast: money -> bigint\n\n-- DROP CAST (money AS bigint);\n\nCREATE CAST (money AS bigint)\n\tWITHOUT FUNCTION;\n\nCOMMENT ON CAST (money AS bigint) IS 'Cast from money to bigint';"
},
{
"type": "delete",
"name": "Drop EXPLICIT Cast",
"endpoint": "NODE-cast.delete_id",
"data": {
"name": "money->bigint"
}
}
]
}
@@ -11,6 +11,5 @@ from pgadmin.utils.route import BaseTestGenerator
class CollationTestGenerator(BaseTestGenerator):
def generate_tests(self):
def runTest(self):
return
@@ -1192,7 +1192,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
if db_variables is not None:
for row in db_variables:
var_name, var_value = row.split("=")
# The value may contain equals in string, split on
# first equals only
var_name, var_value = row.split("=", 1)
var_dict = {'option': var_name, 'value': var_value}
@@ -0,0 +1,8 @@
SELECT
oid as conoid, conname, contype, pg_get_constraintdef(oid, true) as consrc,
connoinherit, convalidated, conislocal
FROM
pg_constraint
WHERE
conrelid={{foid}}::oid
ORDER by conname;
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.proargnames %}{{data.proargnames}}{% endif %})
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}()
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}({% if data.proargnames %}{{data.proargnames}}{% endif %})
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}()
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}()
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}()
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -4,7 +4,8 @@
{% set is_columns = [] %}
{% if data %}
CREATE FUNCTION {{ conn|qtIdent(data.pronamespace, data.name) }}()
RETURNS{% if data.proretset %} SETOF{% endif %} {{ conn|qtTypeIdent(data.prorettypename) }}
RETURNS{% if data.proretset and data.prorettypename.startswith('SETOF ') %} {{ data.prorettypename }} {% elif data.proretset %} SETOF {{ data.prorettypename }}{% else %} {{ data.prorettypename }}{% endif %}
LANGUAGE {{ data.lanname|qtLiteral }}
{% if data.procost %}
COST {{data.procost}}
@@ -11,6 +11,5 @@ from pgadmin.utils.route import BaseTestGenerator
class SynonymTestGenerator(BaseTestGenerator):
def generate_tests(self):
def runTest(self):
return
@@ -74,6 +74,42 @@ class TableModule(SchemaChildModule):
"""
return database.DatabaseModule.NODE_TYPE
@property
def csssnippets(self):
"""
Returns a snippet of css to include in the page
"""
snippets = [
render_template(
"browser/css/collection.css",
node_type=self.node_type,
),
render_template(
"browser/css/node.css",
node_type=self.node_type,
),
render_template(
"browser/css/node.css",
node_type='table',
file_name='table-inherited',
),
render_template(
"browser/css/node.css",
node_type='table',
file_name='table-inherits',
),
render_template(
"browser/css/node.css",
node_type='table',
file_name='table-multi-inherit',
),
]
for submodule in self.submodules:
snippets.extend(submodule.csssnippets)
return snippets
def get_own_javascripts(self):
scripts = SchemaChildModule.get_own_javascripts(self)
@@ -271,6 +307,28 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
status=200
)
def get_icon_css_class(self, table_info, default_val='icon-table'):
if ('is_inherits' in table_info and
table_info['is_inherits'] == '1') or \
('coll_inherits' in table_info and
len(table_info['coll_inherits']) > 0):
if ('is_inherited' in table_info and
table_info['is_inherited'] == '1')\
or ('inherited_tables_cnt' in table_info and
len(table_info['inherited_tables_cnt']) > 0):
default_val = 'icon-table-multi-inherit'
else:
default_val = 'icon-table-inherits'
elif ('is_inherited' in table_info and
table_info['is_inherited'] == '1')\
or ('inherited_tables_cnt' in table_info and
len(table_info['inherited_tables_cnt']) > 0):
default_val = 'icon-table-inherited'
return super(TableView, self).\
get_icon_css_class(table_info, default_val)
@BaseTableView.check_precondition
def node(self, gid, sid, did, scid, tid):
"""
@@ -17,7 +17,7 @@ class BasePartitionTable:
return True
return False
def get_icon_css_class(self, table_info):
def get_icon_css_class(self, table_info, default_val='icon-table'):
if self.is_table_partitioned(table_info):
return 'icon-partition'
return 'icon-table'
return default_val
@@ -230,6 +230,7 @@ define('pgadmin.node.column', [
if (
m.top && ((
!_.isUndefined(m.top.get('oid')) &&
!_.isUndefined(m.top.get('primary_key')) &&
m.top.get('primary_key').length > 0 &&
!_.isUndefined(m.top.get('primary_key').first().get('oid'))
) || (
@@ -255,6 +256,7 @@ define('pgadmin.node.column', [
}
// If primary key already exist then disable.
if (m.top && !_.isUndefined(m.top.get('oid')) &&
!_.isUndefined(m.top.get('primary_key')) &&
m.top.get('primary_key').length > 0 &&
!_.isUndefined(m.top.get('primary_key').first().get('oid'))) {
@@ -190,7 +190,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'delete': [{'delete': 'delete'}],
'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
'children': [{'get': 'children'}],
'sql': [{'get': 'sql'}],
@@ -591,7 +591,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
return internal_server_error(errormsg=str(e))
@BaseTableView.check_precondition
def delete(self, gid, sid, did, scid, tid, ptid):
def delete(self, gid, sid, did, scid, tid, ptid=None):
"""
This function will delete the table object
@@ -601,31 +601,47 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
did: Database ID
scid: Schema ID
tid: Table ID
ptid: Partition Table ID
"""
if ptid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [ptid]}
try:
SQL = render_template(
"/".join([self.partition_template_path, 'properties.sql']),
did=did, scid=scid, tid=tid, ptid=ptid,
datlastsysoid=self.datlastsysoid
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified partition could not be found.\n'
)
for ptid in data['ids']:
SQL = render_template(
"/".join([self.partition_template_path, 'properties.sql']),
did=did, scid=scid, tid=tid, ptid=ptid,
datlastsysoid=self.datlastsysoid
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return super(PartitionsView, self).delete(
gid, sid, did, scid, tid, res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified partition could not be found.\n'
)
)
status, res = super(PartitionsView, self).delete(
gid, sid, did, scid, tid, res)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Partition dropped")
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#f2f2f2;}.cls-2{fill:#c1cbd5;}.cls-3{fill:#2195e7;}.cls-4{fill:#34495e;}</style></defs><title>inherited</title><g id="_10" data-name="10"><rect class="cls-1" x="2.5" y="3" width="11" height="10" rx="1"/><polygon class="cls-2" points="13 9.13 8.38 9.13 8.38 6 7.63 6 7.63 9.13 3 9.13 3 9.88 7.63 9.88 7.63 13 8.38 13 8.38 9.88 13 9.88 13 9.13"/><path class="cls-3" d="M12.5,3h-9a1,1,0,0,0-1,1v8a1,1,0,0,0,1,1h9a1,1,0,0,0,1-1V4A1,1,0,0,0,12.5,3Zm0,.75a.25.25,0,0,1,.25.25V6.12H8.38V3.75Zm-9,0H7.62V6.12H3.25V4A.25.25,0,0,1,3.5,3.75Zm9,8.5h-9A.25.25,0,0,1,3.25,12V6.88h9.5V12A.25.25,0,0,1,12.5,12.25Z"/><path class="cls-1" d="M12,8a3.93,3.93,0,1,1,3.93-3.93A3.94,3.94,0,0,1,12,8Z"/><path class="cls-4" d="M12,.25a3.8,3.8,0,1,1-3.8,3.8A3.8,3.8,0,0,1,12,.25M12,0A4.05,4.05,0,1,0,16,4.05,4,4,0,0,0,12,0Z"/><path class="cls-4" d="M11.77,1.93a.54.54,0,0,0,0,.76l.82.82H10a.54.54,0,0,0,0,1.08h2.58l-.82.82a.54.54,0,1,0,.76.76l1.74-1.74a.53.53,0,0,0,0-.76L12.53,1.93A.54.54,0,0,0,11.77,1.93Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#f2f2f2;}.cls-2{fill:#c1cbd5;}.cls-3{fill:#2195e7;}.cls-4{fill:#34495e;}</style></defs><title>inherits</title><g id="_10" data-name="10"><rect class="cls-1" x="2.5" y="3" width="11" height="10" rx="1"/><polygon class="cls-2" points="13 9.13 8.38 9.13 8.38 6 7.63 6 7.63 9.13 3 9.13 3 9.88 7.63 9.88 7.63 13 8.38 13 8.38 9.88 13 9.88 13 9.13"/><path class="cls-3" d="M12.5,3h-9a1,1,0,0,0-1,1v8a1,1,0,0,0,1,1h9a1,1,0,0,0,1-1V4A1,1,0,0,0,12.5,3Zm0,.75a.25.25,0,0,1,.25.25V6.12H8.38V3.75Zm-9,0H7.62V6.12H3.25V4A.25.25,0,0,1,3.5,3.75Zm9,8.5h-9A.25.25,0,0,1,3.25,12V6.88h9.5V12A.25.25,0,0,1,12.5,12.25Z"/><path class="cls-1" d="M12,8a3.93,3.93,0,1,1,3.93-3.93A3.94,3.94,0,0,1,12,8Z"/><path class="cls-4" d="M12,.25a3.8,3.8,0,1,1-3.8,3.8A3.8,3.8,0,0,1,12,.25M12,0A4.05,4.05,0,1,0,16,4.05,4,4,0,0,0,12,0Z"/><path class="cls-4" d="M12.13,1.93a.54.54,0,0,1,0,.76l-.82.82h2.58a.54.54,0,0,1,0,1.08H11.31l.82.82a.54.54,0,1,1-.76.76L9.63,4.43a.53.53,0,0,1,0-.76l1.74-1.74A.54.54,0,0,1,12.13,1.93Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#f2f2f2;}.cls-2{fill:#c1cbd5;}.cls-3{fill:#2195e7;}.cls-4{fill:#34495e;}</style></defs><title>multiple</title><g id="_10" data-name="10"><rect class="cls-1" x="2.5" y="3" width="11" height="10" rx="1"/><polygon class="cls-2" points="13 9.13 8.38 9.13 8.38 6 7.63 6 7.63 9.13 3 9.13 3 9.88 7.63 9.88 7.63 13 8.38 13 8.38 9.88 13 9.88 13 9.13"/><path class="cls-3" d="M12.5,3h-9a1,1,0,0,0-1,1v8a1,1,0,0,0,1,1h9a1,1,0,0,0,1-1V4A1,1,0,0,0,12.5,3Zm0,.75a.25.25,0,0,1,.25.25V6.12H8.38V3.75Zm-9,0H7.62V6.12H3.25V4A.25.25,0,0,1,3.5,3.75Zm9,8.5h-9A.25.25,0,0,1,3.25,12V6.88h9.5V12A.25.25,0,0,1,12.5,12.25Z"/><path class="cls-1" d="M12,8a3.93,3.93,0,1,1,3.93-3.93A3.94,3.94,0,0,1,12,8Z"/><path class="cls-4" d="M12,.25a3.8,3.8,0,1,1-3.8,3.8A3.8,3.8,0,0,1,12,.25M12,0A4.05,4.05,0,1,0,16,4.05,4,4,0,0,0,12,0Z"/><path class="cls-4" d="M14.94,3.71,13.38,2.14a.49.49,0,0,0-.69.69l.73.73H10.48l.73-.73a.49.49,0,0,0-.69-.69L9,3.71a.48.48,0,0,0,0,.68L10.52,6a.49.49,0,1,0,.69-.69l-.73-.73h2.94l-.73.73a.49.49,0,1,0,.69.69l1.56-1.57a.48.48,0,0,0,0-.68Z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -342,12 +342,32 @@ define('pgadmin.node.table', [
}, cache_node: 'database', cache_level: 'database',
},{
id: 'spcname', label: gettext('Tablespace'), node: 'tablespace',
type: 'text', control: 'node-list-by-name', disabled: 'inSchema',
type: 'text', control: 'node-list-by-name',
mode: ['properties', 'create', 'edit'],
filter: function(d) {
// If tablespace name is not "pg_global" then we need to exclude them
return (!(d && d.label.match(/pg_global/)));
},
deps: ['is_partitioned'],
disabled: function(m) {
if(this.node_info && 'catalog' in this.node_info) {
return true;
}
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
&& !_.isUndefined(m.node_info.server.version) &&
m.node_info.server.version >= 120000 &&
m.get('is_partitioned')) {
setTimeout( function() {
m.set('spcname', undefined);
}, 10);
return true;
}
return false;
},
},{
id: 'partition', type: 'group', label: gettext('Partition'),
mode: ['edit', 'create'], min_version: 100000,
@@ -773,7 +793,15 @@ define('pgadmin.node.table', [
},{
id: 'relhasoids', label: gettext('Has OIDs?'), cell: 'switch',
type: 'switch', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', group: gettext('advanced'),
group: gettext('advanced'),
disabled: function(m) {
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
&& !_.isUndefined(m.node_info.server.version) &&
m.node_info.server.version >= 120000)
return true;
return m.inSchema();
},
},{
id: 'relpersistence', label: gettext('Unlogged?'), cell: 'switch',
type: 'switch', mode: ['properties', 'create', 'edit'],
@@ -7,7 +7,7 @@
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
NOT NULL{% endif %}{% if data.defval and data.defval is not none %}
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none %}
DEFAULT {{data.defval}}{% endif %}{% if data.attidentity and data.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif data.attidentity and data.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
{% if data.seqincrement or data.seqcycle or data.seqincrement or data.seqstart or data.seqmin or data.seqmax or data.seqcache %} ( {% endif %}
{% if data.seqincrement is defined and data.seqcycle %}
@@ -7,7 +7,7 @@
ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
ADD COLUMN {{conn|qtIdent(data.name)}} {% if is_sql %}{{data.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, data.cltype, data.attlen, data.attprecision, data.hasSqrBracket) }}{% endif %}{% if data.collspcname %}
COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
NOT NULL{% endif %}{% if data.defval and data.defval is not none %}
NOT NULL{% endif %}{% if data.defval is defined and data.defval is not none %}
DEFAULT {{data.defval}}{% endif %};
{% endif %}
@@ -0,0 +1,83 @@
SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE
(SELECT sp.spcname FROM pg_database dtb
JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid
WHERE dtb.oid = {{ did }}::oid)
END) as spcname,
(select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as parent_schema,
nsp.nspname as schema,
pg_get_userbyid(rel.relowner) AS relowner, rel.relispartition,
rel.relhassubclass, rel.reltuples::bigint, des.description, con.conname, con.conkey,
EXISTS(select 1 FROM pg_trigger
JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
WHERE tgrelid=rel.oid) AS isrepl,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE 'pg\_%') THEN
quote_ident(nspname)||'.'||quote_ident(c.relname)
ELSE quote_ident(c.relname) END AS inherited_tables
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
(SELECT count(*)
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS autovacuum_enabled,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS toast_autovacuum_enabled,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname,
typ.typrelid AS typoid,
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
-- Added for pgAdmin4
(CASE WHEN array_length(rel.reloptions, 1) > 0 THEN true ELSE false END) AS autovacuum_custom,
(CASE WHEN array_length(tst.reloptions, 1) > 0 AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table,
-- Added for partition table
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
(CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme,
{% if ptid %}
(CASE WHEN rel.relispartition THEN pg_get_expr(rel.relpartbound, {{ ptid }}::oid) ELSE '' END) AS partition_value,
(SELECT relname FROM pg_class WHERE oid = {{ tid }}::oid) AS partitioned_table_name
{% else %}
pg_get_expr(rel.relpartbound, rel.oid) AS partition_value
{% endif %}
FROM pg_class rel
LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
LEFT JOIN pg_inherits inh ON inh.inhrelid = rel.oid
LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
WHERE rel.relispartition AND inh.inhparent = {{ tid }}::oid
{% if ptid %} AND rel.oid = {{ ptid }}::oid {% endif %}
ORDER BY rel.relname;
@@ -0,0 +1,83 @@
SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE
(SELECT sp.spcname FROM pg_database dtb
JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid
WHERE dtb.oid = {{ did }}::oid)
END) as spcname,
(select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as parent_schema,
nsp.nspname as schema,
pg_get_userbyid(rel.relowner) AS relowner, rel.relispartition,
rel.relhassubclass, rel.reltuples::bigint, des.description, con.conname, con.conkey,
EXISTS(select 1 FROM pg_trigger
JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
WHERE tgrelid=rel.oid) AS isrepl,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE 'pg\_%') THEN
quote_ident(nspname)||'.'||quote_ident(c.relname)
ELSE quote_ident(c.relname) END AS inherited_tables
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
(SELECT count(*)
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS autovacuum_enabled,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS toast_autovacuum_enabled,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname,
typ.typrelid AS typoid,
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
-- Added for pgAdmin4
(CASE WHEN array_length(rel.reloptions, 1) > 0 THEN true ELSE false END) AS autovacuum_custom,
(CASE WHEN array_length(tst.reloptions, 1) > 0 AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table,
-- Added for partition table
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
(CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme,
{% if ptid %}
(CASE WHEN rel.relispartition THEN pg_get_expr(rel.relpartbound, {{ ptid }}::oid) ELSE '' END) AS partition_value,
(SELECT relname FROM pg_class WHERE oid = {{ tid }}::oid) AS partitioned_table_name
{% else %}
pg_get_expr(rel.relpartbound, rel.oid) AS partition_value
{% endif %}
FROM pg_class rel
LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
LEFT JOIN pg_inherits inh ON inh.inhrelid = rel.oid
LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
WHERE rel.relispartition AND inh.inhparent = {{ tid }}::oid
{% if ptid %} AND rel.oid = {{ ptid }}::oid {% endif %}
ORDER BY rel.relname;
@@ -42,7 +42,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
{% if data.columns and data.columns|length > 0 %}
{% for c in data.columns %}
{% if c.name and c.cltype %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if c.attidentity and c.attidentity != '' %}
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
@@ -1,7 +1,9 @@
SELECT rel.oid, rel.relname AS name,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
(SELECT count(1) FROM pg_inherits WHERE inhrelid=rel.oid LIMIT 1) as is_inherits,
(SELECT count(1) FROM pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited
FROM pg_class rel
WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
AND NOT rel.relispartition
@@ -0,0 +1,182 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'macros/variable.macros' as VARIABLE %}
{% import 'columns/macros/security.macros' as COLUMN_SECLABEL %}
{% import 'columns/macros/privilege.macros' as COLUMN_PRIVILEGE %}
{% import 'tables/sql/macros/constraints.macro' as CONSTRAINTS %}
{% import 'types/macros/get_full_type_sql_format.macros' as GET_TYPE %}
{#===========================================#}
{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
{#===========================================#}
{#
If user has not provided any details but only name then
add empty bracket with table name
#}
{% set empty_bracket = ""%}
{% if data.coll_inherits|length == 0 and data.columns|length == 0 and not data.typname and not data.like_relation and data.primary_key|length == 0 and data.unique_constraint|length == 0 and data.foreign_key|length == 0 and data.check_constraint|length == 0 and data.exclude_constraint|length == 0 %}
{% set empty_bracket = "\n(\n)"%}
{% endif %}
{% set with_clause = false%}
{% if data.fillfactor or data.autovacuum_custom or data.autovacuum_enabled or data.toast_autovacuum or data.toast_autovacuum_enabled or (data.autovacuum_enabled and data.vacuum_table|length > 0) or (data.toast_autovacuum_enabled and data.vacuum_toast|length > 0) %}
{% set with_clause = true%}
{% endif %}
CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{{empty_bracket}}
{% if data.typname %}
OF {{ data.typname }}
{% endif %}
{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
(
{% endif %}
{% if data.like_relation %}
LIKE {{ data.like_relation }}{% if data.like_default_value %}
INCLUDING DEFAULTS{% endif %}{% if data.like_constraints %}
INCLUDING CONSTRAINTS{% endif %}{% if data.like_indexes %}
INCLUDING INDEXES{% endif %}{% if data.like_storage %}
INCLUDING STORAGE{% endif %}{% if data.like_comments %}
INCLUDING COMMENTS{% endif %}{% if data.columns|length > 0 %},
{% endif %}
{% endif %}
{### Add columns ###}
{% if data.columns and data.columns|length > 0 %}
{% for c in data.columns %}
{% if c.name and c.cltype %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if c.attidentity and c.attidentity != '' %}
{% if c.attidentity == 'a' %} GENERATED ALWAYS AS IDENTITY{% elif c.attidentity == 'd' %} GENERATED BY DEFAULT AS IDENTITY{% endif %}
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %} ( {% endif %}
{% if c.seqincrement is defined and c.seqcycle %}
CYCLE {% endif %}{% if c.seqincrement is defined and c.seqincrement|int(-1) > -1 %}
INCREMENT {{c.seqincrement|int}} {% endif %}{% if c.seqstart is defined and c.seqstart|int(-1) > -1%}
START {{c.seqstart|int}} {% endif %}{% if c.seqmin is defined and c.seqmin|int(-1) > -1%}
MINVALUE {{c.seqmin|int}} {% endif %}{% if c.seqmax is defined and c.seqmax|int(-1) > -1%}
MAXVALUE {{c.seqmax|int}} {% endif %}{% if c.seqcache is defined and c.seqcache|int(-1) > -1%}
CACHE {{c.seqcache|int}} {% endif %}
{% if c.seqincrement or c.seqcycle or c.seqincrement or c.seqstart or c.seqmin or c.seqmax or c.seqcache %}){% endif %}
{% endif %}
{% if not loop.last %},
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{# Macro to render for constraints #}
{% if data.primary_key|length > 0 %}{% if data.columns|length > 0 %},{% endif %}
{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 %},{% endif %}
{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %}
{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %}
{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %}
{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %}
{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
){% endif %}{% if data.relkind is defined and data.relkind == 'p' %} PARTITION BY {{ data.partition_scheme }} {% endif %}
{% if not data.coll_inherits and (not data.spcname or (data.spcname and data.is_partitioned)) and not with_clause %};{% endif %}
{### If we are inheriting it from another table(s) ###}
{% if data.coll_inherits %}
INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %}){% if not data.spcname and not with_clause %};{% endif %}
{% endif %}
{% if with_clause %}
{% set add_comma = false%}
WITH (
{% if data.fillfactor %}{% set add_comma = true%}
FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.autovacuum_custom %}
{% if add_comma %},
{% endif %}
autovacuum_enabled = {% if data.autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}{% set add_comma = true%}{% endif %}{% if data.toast_autovacuum %}
{% if add_comma %},
{% endif %}
toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}
{% endif %}{% if data.autovacuum_enabled and data.vacuum_table|length > 0 %}
{% for opt in data.vacuum_table %}{% if opt.name and opt.value %}
,
{{opt.name}} = {{opt.value}}{% endif %}
{% endfor %}{% endif %}{% if data.toast_autovacuum_enabled and data.vacuum_toast|length > 0 %}
{% for opt in data.vacuum_toast %}{% if opt.name and opt.value %}
,
toast.{{opt.name}} = {{opt.value}}{% endif %}
{% endfor %}{% endif %}
{% if data.spcname and not data.is_partitioned %}){% else %});{% endif %}
{% endif %}
{### SQL for Tablespace ###}
{% if data.spcname and not data.is_partitioned %}
TABLESPACE {{ conn|qtIdent(data.spcname) }};
{% endif %}
{### Alter SQL for Owner ###}
{% if data.relowner %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
OWNER to {{conn|qtIdent(data.relowner)}};
{% endif %}
{### Security Labels on Table ###}
{% if data.seclabels and data.seclabels|length > 0 %}
{% for r in data.seclabels %}
{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
{% endfor %}
{% endif %}
{### ACL on Table ###}
{% if data.relacl %}
{% for priv in data.relacl %}
{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{### SQL for COMMENT ###}
{% if data.description %}
COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral}};
{% endif %}
{#===========================================#}
{#====== MAIN TABLE TEMPLATE ENDS HERE ======#}
{#===========================================#}
{#===========================================#}
{# COLUMN SPECIFIC TEMPLATES STARTS HERE #}
{#===========================================#}
{% if data.columns and data.columns|length > 0 %}
{% for c in data.columns %}
{% if c.description %}
COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.name, c.name)}}
IS {{c.description|qtLiteral}};
{% endif %}
{### Add variables to column ###}
{% if c.attoptions and c.attoptions|length > 0 %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
{{ VARIABLE.SET(conn, 'COLUMN', c.name, c.attoptions) }}
{% endif %}
{### ACL ###}
{% if c.attacl and c.attacl|length > 0 %}
{% for priv in c.attacl %}
{{ COLUMN_PRIVILEGE.APPLY(conn, data.schema, data.name, c.name, priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{### Security Lables ###}
{% if c.seclabels and c.seclabels|length > 0 %}
{% for r in c.seclabels %}
{{ COLUMN_SECLABEL.APPLY(conn, 'COLUMN',data.schema, data.name, c.name, r.provider, r.label) }}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{#===========================================#}
{# COLUMN SPECIFIC TEMPLATES ENDS HERE #}
{#===========================================#}
{#======================================#}
{# CONSTRAINTS SPECIFIC TEMPLATES #}
{#======================================#}
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.primary_key)}}
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.unique_constraint)}}
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}}
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}}
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}}
@@ -0,0 +1,8 @@
SELECT cl.oid as value, quote_ident(nspname)||'.'||quote_ident(relname) AS label
FROM pg_namespace nsp, pg_class cl
WHERE relnamespace=nsp.oid AND relkind in ('r', 'p')
AND nsp.nspname NOT LIKE E'pg\_temp\_%'
{% if not show_sysobj %}
AND (nsp.nspname NOT LIKE 'pg\_%' AND nsp.nspname NOT in ('information_schema'))
{% endif %}
ORDER BY nspname, relname
@@ -0,0 +1,75 @@
SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
(CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE
(SELECT sp.spcname FROM pg_database dtb
JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid
WHERE dtb.oid = {{ did }}::oid)
END) as spcname,
(select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as schema,
pg_get_userbyid(rel.relowner) AS relowner, rel.relkind,
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
rel.relhassubclass, rel.reltuples::bigint, des.description, con.conname, con.conkey,
EXISTS(select 1 FROM pg_trigger
JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
WHERE tgrelid=rel.oid) AS isrepl,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE 'pg\_%') THEN
quote_ident(nspname)||'.'||quote_ident(c.relname)
ELSE quote_ident(c.relname) END AS inherited_tables
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
(SELECT count(*)
FROM pg_inherits i
JOIN pg_class c ON c.oid = i.inhparent
JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS autovacuum_enabled,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
THEN true ELSE false END) AS toast_autovacuum_enabled,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
typ.typrelid AS typoid,
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
-- Added for pgAdmin4
(CASE WHEN array_length(rel.reloptions, 1) > 0 THEN true ELSE false END) AS autovacuum_custom,
(CASE WHEN array_length(tst.reloptions, 1) > 0 AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
-- Added for partition table
{% if tid %}, (CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef({{ tid }}::oid) ELSE '' END) AS partition_scheme {% endif %}
FROM pg_class rel
LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
AND NOT rel.relispartition
{% if tid %} AND rel.oid = {{ tid }}::oid {% endif %}
ORDER BY rel.relname;
@@ -0,0 +1,211 @@
{% import 'macros/schemas/security.macros' as SECLABEL %}
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
{% import 'macros/variable.macros' as VARIABLE %}
{#####################################################}
{## Rename table ##}
{#####################################################}
{% if data.name and data.name != o_data.name %}
ALTER TABLE {{conn|qtIdent(o_data.schema, o_data.name)}}
RENAME TO {{conn|qtIdent(data.name)}};
{% endif %}
{#####################################################}
{## Change table schema ##}
{#####################################################}
{% if data.schema and data.schema != o_data.schema %}
ALTER TABLE {{conn|qtIdent(o_data.schema, data.name)}}
SET SCHEMA {{conn|qtIdent(data.schema)}};
{% endif %}
{#####################################################}
{## Change table owner ##}
{#####################################################}
{% if data.relowner and data.relowner != o_data.relowner %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
OWNER TO {{conn|qtIdent(data.relowner)}};
{% endif %}
{#####################################################}
{## Update Inherits table definition ##}
{#####################################################}
{% if data.coll_inherits_added|length > 0 %}
{% for val in data.coll_inherits_added %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
INHERIT {{val}};
{% endfor %}
{% endif %}
{% if data.coll_inherits_removed|length > 0 %}
{% for val in data.coll_inherits_removed %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
NO INHERIT {{val}};
{% endfor %}
{% endif %}
{#####################################################}
{## Change tablespace ##}
{#####################################################}
{% if data.spcname and data.spcname != o_data.spcname %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
SET TABLESPACE {{conn|qtIdent(data.spcname)}};
{% endif %}
{#####################################################}
{## change fillfactore settings ##}
{#####################################################}
{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
SET (FILLFACTOR={{data.fillfactor}});
{% endif %}
{###############################}
{## Table AutoVacuum settings ##}
{###############################}
{% if data.vacuum_table is defined and data.vacuum_table.set_values|length > 0 %}
{% set has_vacuum_set = true %}
{% endif %}
{% if data.vacuum_table is defined and data.vacuum_table.reset_values|length > 0 %}
{% set has_vacuum_reset = true %}
{% endif %}
{% if o_data.autovacuum_custom and data.autovacuum_custom == false %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
autovacuum_enabled,
autovacuum_analyze_scale_factor,
autovacuum_analyze_threshold,
autovacuum_freeze_max_age,
autovacuum_vacuum_cost_delay,
autovacuum_vacuum_cost_limit,
autovacuum_vacuum_scale_factor,
autovacuum_vacuum_threshold,
autovacuum_freeze_min_age,
autovacuum_freeze_table_age
);
{% else %}
{% if data.autovacuum_enabled is defined or has_vacuum_set %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
{% if data.autovacuum_enabled is defined and data.autovacuum_enabled != o_data.autovacuum_enabled %}
autovacuum_enabled = {% if data.autovacuum_enabled %}true{% else %}false{% endif %}{% if has_vacuum_set %},
{% endif %}
{% endif %}
{% if has_vacuum_set %}
{% for opt in data.vacuum_table.set_values %}{% if opt.name and opt.value %}
{{opt.name}} = {{opt.value}}{% if not loop.last %},
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
);
{% endif %}
{% if has_vacuum_reset %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
{% for opt in data.vacuum_table.reset_values %}{% if opt.name %}
{{opt.name}}{% if not loop.last %},
{% endif %}
{% endif %}
{% endfor %}
);
{% endif %}
{% endif %}
{#####################################}
{## Toast table AutoVacuum settings ##}
{#####################################}
{% if data.vacuum_toast is defined and data.vacuum_toast.set_values|length > 0 %}
{% set has_vacuum_toast_set = true %}
{% endif %}
{% if data.vacuum_toast is defined and data.vacuum_toast.reset_values|length > 0 %}
{% set has_vacuum_toast_reset = true %}
{% endif %}
{% if o_data.toast_autovacuum and data.toast_autovacuum == false %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
toast.autovacuum_enabled,
toast.autovacuum_freeze_max_age,
toast.autovacuum_vacuum_cost_delay,
toast.autovacuum_vacuum_cost_limit,
toast.autovacuum_vacuum_scale_factor,
toast.autovacuum_vacuum_threshold,
toast.autovacuum_freeze_min_age,
toast.autovacuum_freeze_table_age,
toast.autovacuum_analyze_threshold,
toast.autovacuum_analyze_scale_factor
);
{% else %}
{% if data.toast_autovacuum_enabled is defined or has_vacuum_toast_set %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
{% if data.toast_autovacuum_enabled is defined and data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled %}
toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled %}true{% else %}false{% endif %}{% if has_vacuum_toast_set %},
{% endif %}
{% endif %}
{% if has_vacuum_toast_set %}
{% for opt in data.vacuum_toast.set_values %}{% if opt.name and opt.value %}
toast.{{opt.name}} = {{opt.value}}{% if not loop.last %},
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
);
{% endif %}
{% if has_vacuum_toast_reset %}
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
{% for opt in data.vacuum_toast.reset_values %}{% if opt.name %}
toast.{{opt.name}}{% if not loop.last %},
{% endif %}
{% endif %}
{% endfor %}
);
{% endif %}
{% endif %}
{#####################################################}
{## Change table comments ##}
{#####################################################}
{% if data.description is defined and data.description != o_data.description %}
COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral}};
{% endif %}
{#####################################################}
{## Update table Privileges ##}
{#####################################################}
{% if data.relacl %}
{% if 'deleted' in data.relacl %}
{% for priv in data.relacl.deleted %}
{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.relacl %}
{% for priv in data.relacl.changed %}
{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in data.relacl %}
{% for priv in data.relacl.added %}
{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
{#####################################################}
{## Update table SecurityLabel ##}
{#####################################################}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.UNSET(conn, 'TABLE', data.name, r.provider, data.schema) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
{% endfor %}
{% endif %}
{% endif %}
@@ -1,6 +1,8 @@
SELECT rel.oid, rel.relname AS name,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
(SELECT count(1) FROM pg_inherits WHERE inhrelid=rel.oid LIMIT 1) as is_inherits,
(SELECT count(1) FROM pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited
FROM pg_class rel
WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
{% if tid %} AND rel.oid = {{tid}}::OID {% endif %}
@@ -42,7 +42,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
{% if data.columns and data.columns|length > 0 %}
{% for c in data.columns %}
{% if c.name and c.cltype %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if not loop.last %},
{% endif %}
{% endif %}
@@ -1,6 +1,8 @@
SELECT rel.oid, rel.relname AS name,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid) AS triggercount,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers,
(SELECT count(1) FROM pg_inherits WHERE inhrelid=rel.oid LIMIT 1) as is_inherits,
(SELECT count(1) FROM pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited
FROM pg_class rel
WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
{% if tid %} AND rel.oid = {{tid}}::OID {% endif %}
@@ -42,7 +42,7 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
{% if data.columns and data.columns|length > 0 %}
{% for c in data.columns %}
{% if c.name and c.cltype %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %}
{% if c.inheritedfromtable %}-- Inherited from table {{c.inheritedfromtable}}: {% elif c.inheritedfromtype %}-- Inherited from type {{c.inheritedfromtype}}: {% endif %}{{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval is defined and c.defval is not none %} DEFAULT {{c.defval}}{% endif %}
{% if not loop.last %},
{% endif %}
{% endif %}
@@ -1,7 +1,9 @@
SELECT rel.oid, rel.relname AS name,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid) AS triggercount,
(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgenabled = 'O') AS has_enable_triggers,
(CASE WHEN (SELECT count(*) from pg_partition where parrelid = rel.oid) > 0 THEN true ELSE false END) AS is_partitioned
(CASE WHEN (SELECT count(*) from pg_partition where parrelid = rel.oid) > 0 THEN true ELSE false END) AS is_partitioned,
(SELECT count(1) FROM pg_inherits WHERE inhrelid=rel.oid LIMIT 1) as is_inherits,
(SELECT count(1) FROM pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited
FROM pg_class rel
WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
AND rel.relname NOT IN (SELECT partitiontablename FROM pg_partitions)
@@ -35,7 +35,10 @@ class TestColumnAclSql(SQLTemplateTestBase):
self.table_id, self.column_id = cursor.fetchone()
def generate_sql(self, version):
template_file = self.get_template_file(version, "acl.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"columns", "sql")
template_file = self.get_template_file(version, file_path,
"acl.sql")
template = file_as_template(template_file)
public_schema_id = 2200
sql = template.render(scid=public_schema_id,
@@ -47,10 +50,3 @@ class TestColumnAclSql(SQLTemplateTestBase):
def assertions(self, fetch_result, descriptions):
self.assertEqual(0, len(fetch_result))
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "columns", "sql",
version, filename
)
@@ -30,7 +30,10 @@ class TestColumnPropertiesSql(SQLTemplateTestBase):
self.table_id = cursor.fetchone()[0]
def generate_sql(self, version):
template_file = self.get_template_file(version, "properties.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"columns", "sql")
template_file = self.get_template_file(version, file_path,
"properties.sql")
template = file_as_template(template_file)
public_schema_id = 2200
sql = template.render(scid=public_schema_id,
@@ -47,10 +50,3 @@ class TestColumnPropertiesSql(SQLTemplateTestBase):
self.assertEqual('some_column', first_row['name'])
self.assertEqual('character varying', first_row['cltype'])
self.assertEqual(3, len(fetch_result))
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "columns", "sql",
version, filename
)
@@ -30,7 +30,10 @@ class TestTablesAclSql(SQLTemplateTestBase):
self.table_id = cursor.fetchone()[0]
def generate_sql(self, version):
template_file = self.get_template_file(version, "acl.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"tables", "sql")
template_file = self.get_template_file(version, file_path,
"acl.sql")
template = file_as_template(template_file)
public_schema_id = 2200
sql = template.render(scid=public_schema_id,
@@ -53,10 +56,3 @@ class TestTablesAclSql(SQLTemplateTestBase):
self.assertEqual(['r'], new_acl_map['privileges'])
self.assertEqual([False], new_acl_map['grantable'])
return public_acls
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "tables", "sql",
version, filename
)
@@ -28,7 +28,10 @@ class TestTablesNodeSql(SQLTemplateTestBase):
pass
def generate_sql(self, version):
template_file = self.get_template_file(version, "nodes.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"tables", "sql")
template_file = self.get_template_file(version, file_path,
"nodes.sql")
template = file_as_template(template_file)
public_schema_id = 2200
sql = template.render(scid=public_schema_id)
@@ -50,10 +53,3 @@ class TestTablesNodeSql(SQLTemplateTestBase):
# triggercount is sometimes returned as a string for some reason
self.assertEqual(0, long(triggercount))
self.assertIsNotNone(long(has_enable_triggers))
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "tables", "sql",
version, filename
)
@@ -44,7 +44,10 @@ class TestTablesPropertiesSql(SQLTemplateTestBase):
self.assertEqual([], first_row['coll_inherits'])
def generate_sql(self, version):
template_file = self.get_template_file(version, "properties.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"tables", "sql")
template_file = self.get_template_file(version, file_path,
"properties.sql")
template = file_as_template(template_file)
public_schema_id = 2200
sql = template.render(scid=public_schema_id,
@@ -66,10 +69,3 @@ class TestTablesPropertiesSql(SQLTemplateTestBase):
cursor.execute("SELECT oid FROM pg_class where relname='test_table'")
self.table_id = cursor.fetchone()[0]
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "tables", "sql",
version, filename
)
@@ -35,7 +35,10 @@ class TestTriggerGetOidSql(SQLTemplateTestBase):
self.table_id, self.column_id = cursor.fetchone()
def generate_sql(self, version):
template_file = self.get_template_file(version, "get_oid.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"triggers", "sql")
template_file = self.get_template_file(version, file_path,
"get_oid.sql")
jinja2.filters.FILTERS['qtLiteral'] = lambda value: "NULL"
template = file_as_template(template_file)
@@ -47,10 +50,3 @@ class TestTriggerGetOidSql(SQLTemplateTestBase):
def assertions(self, fetch_result, descriptions):
self.assertEqual(0, len(fetch_result))
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "triggers", "sql",
version, filename
)
@@ -30,7 +30,10 @@ class TestTriggerNodesSql(SQLTemplateTestBase):
self.table_id = cursor.fetchone()[0]
def generate_sql(self, version):
template_file = self.get_template_file(version, "nodes.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"triggers", "sql")
template_file = self.get_template_file(version, file_path,
"nodes.sql")
template = file_as_template(template_file)
sql = template.render(tid=self.table_id)
@@ -38,10 +41,3 @@ class TestTriggerNodesSql(SQLTemplateTestBase):
def assertions(self, fetch_result, descriptions):
self.assertEqual(0, len(fetch_result))
@staticmethod
def get_template_file(version, filename):
return os.path.join(
os.path.dirname(__file__), "..", "templates", "triggers", "sql",
version, filename
)
@@ -1765,21 +1765,22 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
status, res = self.conn.execute_dict(properties_sql)
if not status:
return internal_server_error(errormsg=res)
old_data = res['rows'][0]
old_col_data = res['rows'][0]
old_data['cltype'], old_data['hasSqrBracket'] = \
self._cltype_formatter(old_data['cltype'])
old_data = \
old_col_data['cltype'], \
old_col_data['hasSqrBracket'] = \
self._cltype_formatter(old_col_data['cltype'])
old_col_data = \
BaseTableView.convert_length_precision_to_string(
old_data
old_col_data
)
fulltype = self.get_full_type(
old_data['typnspname'],
old_data['typname'],
old_data['isdup'],
old_data['attndims'],
old_data['atttypmod']
old_col_data['typnspname'],
old_col_data['typname'],
old_col_data['isdup'],
old_col_data['attndims'],
old_col_data['atttypmod']
)
def get_type_attr(key, data):
@@ -1790,9 +1791,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
# If the column data type has not changed then fetch
# old length and precision
if 'elemoid' in old_data and 'cltype' not in c:
if 'elemoid' in old_col_data and 'cltype' not in c:
length, precision, typeval = \
self.get_length_precision(old_data['elemoid'])
self.get_length_precision(
old_col_data['elemoid'])
# If we have length & precision both
if length and precision:
@@ -1828,25 +1830,25 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
# datatype to new one.
if not length:
old_data['attlen'] = -1
old_col_data['attlen'] = -1
if not precision:
old_data['attprecision'] = None
old_col_data['attprecision'] = None
old_data['cltype'] = DataTypeReader.parse_type_name(
old_data['cltype']
)
old_col_data['cltype'] = \
DataTypeReader.parse_type_name(
old_col_data['cltype'])
if int(old_data['attlen']) == -1:
old_data['attlen'] = None
if 'attprecision' not in old_data:
old_data['attprecision'] = None
if int(old_col_data['attlen']) == -1:
old_col_data['attlen'] = None
if 'attprecision' not in old_col_data:
old_col_data['attprecision'] = None
# Sql for alter column
if 'inheritedfrom' not in c:
column_sql += render_template("/".join(
[self.column_template_path, 'update.sql']),
data=c, o_data=old_data, conn=self.conn
data=c, o_data=old_col_data, conn=self.conn
).strip('\n') + '\n\n'
# If column(s) is/are added
@@ -1911,7 +1913,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
self.get_partitions_sql(temp_data).strip('\n') + '\n\n'
# Combine all the SQL together
SQL += partitions_sql.strip('\n')
SQL += '\n' + partitions_sql.strip('\n')
# Check if index constraints are added/changed/deleted
index_constraint_sql = self.get_index_constraint_sql(
@@ -51,7 +51,7 @@ class TypesAddTestCase(BaseTestGenerator):
"typtype": "c",
"typeowner": db_user,
"schema": self.schema_name,
"composite": [{"member_name": "one", "type": "abstime",
"composite": [{"member_name": "one", "type": "bigint",
"is_tlength": False, "is_precision": False},
{"member_name": "two", "type": "\"char\"[]",
"is_tlength": False, "is_precision": False}],
@@ -11,6 +11,5 @@ from pgadmin.utils.route import BaseTestGenerator
class ViewsTestGenerator(BaseTestGenerator):
def generate_tests(self):
def runTest(self):
return
@@ -918,19 +918,19 @@ define('pgadmin.node.server', [
id: 'tunnel_host', label: gettext('Tunnel host'), type: 'text', group: gettext('SSH Tunnel'),
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
disabled: function(model) {
return !model.get('use_ssh_tunnel');
return !model.get('use_ssh_tunnel') || model.get('connected');
},
},{
id: 'tunnel_port', label: gettext('Tunnel port'), type: 'int', group: gettext('SSH Tunnel'),
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'], max: 65535,
disabled: function(model) {
return !model.get('use_ssh_tunnel');
return !model.get('use_ssh_tunnel') || model.get('connected');
},
},{
id: 'tunnel_username', label: gettext('Username'), type: 'text', group: gettext('SSH Tunnel'),
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
disabled: function(model) {
return !model.get('use_ssh_tunnel');
return !model.get('use_ssh_tunnel') || model.get('connected');
},
},{
id: 'tunnel_authentication', label: gettext('Authentication'), type: 'switch',
@@ -939,7 +939,7 @@ define('pgadmin.node.server', [
'offText': gettext('Password'), 'size': 'mini', width: '90'},
deps: ['use_ssh_tunnel'],
disabled: function(model) {
return !model.get('use_ssh_tunnel');
return !model.get('use_ssh_tunnel') || model.get('connected');
},
}, {
id: 'tunnel_identity_file', label: gettext('Identity file'), type: 'text',
@@ -963,7 +963,7 @@ define('pgadmin.node.server', [
group: gettext('SSH Tunnel'), control: 'input', mode: ['create'],
deps: ['use_ssh_tunnel'],
disabled: function(model) {
return !model.get('use_ssh_tunnel');
return !model.get('use_ssh_tunnel') || model.get('connected');
},
}, {
id: 'save_tunnel_password', controlLabel: gettext('Save password?'),
@@ -0,0 +1,51 @@
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN cl.relkind || COALESCE(dep.refobjsubid::character varying, '')
WHEN tg.oid IS NOT NULL THEN 'T'::text
WHEN ty.oid IS NOT NULL AND ty.typbasetype = 0 THEN 'y'::text
WHEN ty.oid IS NOT NULL AND ty.typbasetype != 0 THEN 'd'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
WHEN ad.oid IS NOT NULL THEN 'A'::text
WHEN fs.oid IS NOT NULL THEN 'F'::text
WHEN fdw.oid IS NOT NULL THEN 'f'::text
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_proc pr ON dep.refobjid=pr.oid
LEFT JOIN pg_namespace nsp ON pr.pronamespace=nsp.oid
LEFT JOIN pg_trigger tg ON dep.refobjid=tg.oid
LEFT JOIN pg_type ty ON dep.refobjid=ty.oid
LEFT JOIN pg_namespace nst ON ty.typnamespace=nst.oid
LEFT JOIN pg_constraint co ON dep.refobjid=co.oid
LEFT JOIN pg_class coc ON co.conrelid=coc.oid
LEFT JOIN pg_namespace nso ON co.connamespace=nso.oid
LEFT JOIN pg_rewrite rw ON dep.refobjid=rw.oid
LEFT JOIN pg_class clrw ON clrw.oid=rw.ev_class
LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
LEFT JOIN pg_language la ON dep.refobjid=la.oid
LEFT JOIN pg_namespace ns ON dep.refobjid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
LEFT JOIN pg_foreign_server fs ON fs.oid=dep.refobjid
LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.refobjid
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.refobjid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.refobjid)
{{where_clause}} AND
refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
ORDER BY refclassid, cl.relkind
@@ -0,0 +1,50 @@
SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, pg_get_expr(ad.adbin, ad.adrelid) as adsrc,
CASE WHEN cl.relkind IS NOT NULL THEN cl.relkind || COALESCE(dep.objsubid::text, '')
WHEN tg.oid IS NOT NULL THEN 'T'::text
WHEN ty.oid IS NOT NULL THEN 'y'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
WHEN ad.oid IS NOT NULL THEN 'A'::text
WHEN fs.oid IS NOT NULL THEN 'F'::text
WHEN fdw.oid IS NOT NULL THEN 'f'::text
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.objid=cl.oid
LEFT JOIN pg_attribute att ON dep.objid=att.attrelid AND dep.objsubid=att.attnum
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
LEFT JOIN pg_proc pr ON dep.objid=pr.oid
LEFT JOIN pg_namespace nsp ON pr.pronamespace=nsp.oid
LEFT JOIN pg_trigger tg ON dep.objid=tg.oid
LEFT JOIN pg_type ty ON dep.objid=ty.oid
LEFT JOIN pg_namespace nst ON ty.typnamespace=nst.oid
LEFT JOIN pg_constraint co ON dep.objid=co.oid
LEFT JOIN pg_class coc ON co.conrelid=coc.oid
LEFT JOIN pg_namespace nso ON co.connamespace=nso.oid
LEFT JOIN pg_rewrite rw ON dep.objid=rw.oid
LEFT JOIN pg_class clrw ON clrw.oid=rw.ev_class
LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
LEFT JOIN pg_language la ON dep.objid=la.oid
LEFT JOIN pg_namespace ns ON dep.objid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.oid=dep.objid
LEFT JOIN pg_foreign_server fs ON fs.oid=dep.objid
LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.objid
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.objid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.objid)
{{where_clause}} AND
classid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
ORDER BY classid, cl.relkind
@@ -4,7 +4,8 @@ SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
WHEN ty.oid IS NOT NULL AND ty.typbasetype = 0 THEN 'y'::text
WHEN ty.oid IS NOT NULL AND ty.typbasetype != 0 THEN 'd'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL THEN 'p'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
@@ -14,10 +15,12 @@ SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
@@ -38,8 +41,11 @@ LEFT JOIN pg_namespace ns ON dep.refobjid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
LEFT JOIN pg_foreign_server fs ON fs.oid=dep.refobjid
LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.refobjid
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.refobjid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.refobjid)
{{where_clause}} AND
refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
ORDER BY refclassid, cl.relkind
ORDER BY refclassid, cl.relkind
@@ -3,7 +3,8 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
WHEN tg.oid IS NOT NULL THEN 'T'::text
WHEN ty.oid IS NOT NULL THEN 'y'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL THEN 'p'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
@@ -13,10 +14,12 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.objid=cl.oid
LEFT JOIN pg_attribute att ON dep.objid=att.attrelid AND dep.objsubid=att.attnum
@@ -37,6 +40,9 @@ LEFT JOIN pg_namespace ns ON dep.objid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.oid=dep.objid
LEFT JOIN pg_foreign_server fs ON fs.oid=dep.objid
LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.objid
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.objid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.objid)
{{where_clause}} AND
classid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
@@ -5,7 +5,8 @@ SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
WHEN ty.oid IS NOT NULL AND ty.typbasetype = 0 THEN 'y'::text
WHEN ty.oid IS NOT NULL AND ty.typbasetype != 0 THEN 'd'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL THEN 'p'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
@@ -13,10 +14,12 @@ SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
@@ -35,8 +38,11 @@ LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
LEFT JOIN pg_language la ON dep.refobjid=la.oid
LEFT JOIN pg_namespace ns ON dep.refobjid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.refobjid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.refobjid)
{{where_clause}} AND
refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
ORDER BY refclassid, cl.relkind
ORDER BY refclassid, cl.relkind
@@ -4,7 +4,8 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
WHEN tg.oid IS NOT NULL THEN 'T'::text
WHEN ty.oid IS NOT NULL THEN 'y'::text
WHEN ns.oid IS NOT NULL THEN 'n'::text
WHEN pr.oid IS NOT NULL THEN 'p'::text
WHEN pr.oid IS NOT NULL AND prtyp.typname = 'trigger' THEN 't'::text
WHEN pr.oid IS NOT NULL THEN 'P'::text
WHEN la.oid IS NOT NULL THEN 'l'::text
WHEN rw.oid IS NOT NULL THEN 'R'::text
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
@@ -12,10 +13,12 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
ELSE ''
END AS type,
COALESCE(coc.relname, clrw.relname) AS ownertable,
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || COALESCE('.' || att.attname, '')
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
END AS refname,
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname,
CASE WHEN inhits.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherits,
CASE WHEN inhed.inhparent IS NOT NULL THEN '1' ELSE '0' END AS is_inherited
FROM pg_depend dep
LEFT JOIN pg_class cl ON dep.objid=cl.oid
LEFT JOIN pg_attribute att ON dep.objid=att.attrelid AND dep.objsubid=att.attnum
@@ -34,6 +37,9 @@ LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
LEFT JOIN pg_language la ON dep.objid=la.oid
LEFT JOIN pg_namespace ns ON dep.objid=ns.oid
LEFT JOIN pg_attrdef ad ON ad.oid=dep.objid
LEFT JOIN pg_type prtyp ON prtyp.oid = pr.prorettype
LEFT JOIN pg_inherits inhits ON (inhits.inhrelid=dep.objid)
LEFT JOIN pg_inherits inhed ON (inhed.inhparent=dep.objid)
{{where_clause}} AND
classid IN ( SELECT oid FROM pg_class WHERE relname IN
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
@@ -14,7 +14,7 @@
<div class="save-password-div input-group py-2">
<div class="w-100">
<input id="save_tunnel_password" name="save_tunnel_password" type="checkbox"
{% if not config.ALLOW_SAVE_PASSWORD %}disabled{% endif %}
{% if not config.ALLOW_SAVE_TUNNEL_PASSWORD %}disabled{% endif %}
>
<label for="save_tunnel_password" class="ml-1">Save Password</label>
</div>
@@ -31,7 +31,10 @@ class TestDependenciesSql(SQLTemplateTestBase):
self.table_id = cursor.fetchone()[0]
def generate_sql(self, version):
template_file = self.get_template_file(version, "dependencies.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"depends", "sql")
template_file = self.get_template_file(version, file_path,
"dependencies.sql")
template = file_as_template(template_file)
sql = template.render(
where_clause="WHERE dep.objid=%s::oid" % self.table_id)
@@ -47,8 +50,3 @@ class TestDependenciesSql(SQLTemplateTestBase):
self.assertEqual('n', first_row["deptype"])
self.assertEqual('public', first_row["refname"])
@staticmethod
def get_template_file(version, filename):
return os.path.join(os.path.dirname(__file__), "..", "templates",
"depends", "sql", version, filename)
@@ -31,7 +31,10 @@ class TestDependentsSql(SQLTemplateTestBase):
self.table_id = cursor.fetchone()[0]
def generate_sql(self, version):
template_file = self.get_template_file(version, "dependents.sql")
file_path = os.path.join(os.path.dirname(__file__), "..", "templates",
"depends", "sql")
template_file = self.get_template_file(version, file_path,
"dependents.sql")
template = file_as_template(template_file)
sql = template.render(
where_clause="WHERE dep.objid=%s::oid" % self.table_id)
@@ -47,8 +50,3 @@ class TestDependentsSql(SQLTemplateTestBase):
self.assertEqual('n', first_row["deptype"])
self.assertEqual('test_table', first_row["refname"])
@staticmethod
def get_template_file(version, filename):
return os.path.join(os.path.dirname(__file__), "..", "templates",
"depends", "sql", version, filename)
+5 -19
View File
@@ -12,7 +12,7 @@ define('pgadmin.browser', [
'sources/gettext', 'sources/url_for', 'require', 'jquery', 'underscore', 'underscore.string',
'bootstrap', 'sources/pgadmin', 'pgadmin.alertifyjs', 'bundled_codemirror',
'sources/check_node_visibility', './toolbar', 'pgadmin.help',
'sources/csrf', 'sources/keyboard_shortcuts', 'pgadmin.browser.utils',
'sources/csrf', 'pgadmin.browser.utils',
'wcdocker', 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree',
'pgadmin.browser.preferences', 'pgadmin.browser.messages',
'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin.browser.layout',
@@ -24,7 +24,7 @@ define('pgadmin.browser', [
tree,
gettext, url_for, require, $, _, S,
Bootstrap, pgAdmin, Alertify, codemirror,
checkNodeVisibility, toolBar, help, csrfToken, keyboardFunc
checkNodeVisibility, toolBar, help, csrfToken
) {
window.jQuery = window.$ = $;
// Some scripts do export their object in the window only.
@@ -518,6 +518,9 @@ define('pgadmin.browser', [
this.message = message;
this.reset = reset;
},
build: function() {
Alertify.pgDialogBuild.apply(this);
},
setup:function() {
return {
buttons:[{
@@ -547,30 +550,13 @@ define('pgadmin.browser', [
},
prepare:function() {
let self = this;
let $password = null;
let $okBtn = $(self.__internal.buttons[3].element);
self.setContent(self.message);
$password = $(self.elements.body).find('#password');
/* Reset button hide */
if(!self.reset) {
$(self.__internal.buttons[1].element).addClass('d-none');
} else {
$(self.__internal.buttons[1].element).removeClass('d-none');
}
/* Enable ok only if password entered */
$okBtn.prop('disabled', true);
$password.on('input change keyup', (event)=>{
keyboardFunc._stopEventPropagation(event);
if($password.val() != '') {
$okBtn.prop('disabled', false);
} else {
$okBtn.prop('disabled', true);
}
});
},
callback: function(event) {
let parentDialog = this;
@@ -1,5 +1,8 @@
.icon-{{node_type}} {
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.svg' % node_type )}}') !important;
{% if file_name is not defined %}
{% set file_name=node_type %}
{% endif %}
.icon-{{file_name}} {
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.svg' % file_name )}}') !important;
background-repeat: no-repeat;
background-size: 20px !important;
align-content: center;
@@ -7,8 +10,8 @@
height: 15px;
}
.pgadmin-node-select option[node="{{node_type}}"] {
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.svg' % node_type )}}') !important;
.pgadmin-node-select option[node="{{file_name}}"] {
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.svg' % file_name )}}') !important;
background-repeat: no-repeat;
background-size: 20px !important;
background-position: center left;
@@ -78,7 +78,6 @@ require.onResourceLoad = function (context, map, depMaps) {
window.onload = function(e){
setTimeout(function() {
var gravatarImg = {{ IMG.PREPARE_HTML()|safe }}
//$('#navbar-menu .navbar-right > li > a').html(gravatarImg);
var navbarUser = document.getElementById("navbar-user");
if (navbarUser) {
navbarUser.innerHTML = gravatarImg;
@@ -88,6 +87,10 @@ window.onload = function(e){
{% endif %}
{% endblock %}
{% block css_link %}
<link type="text/css" rel="stylesheet" href="{{ url_for('browser.browser_css')}}"/>
{% endblock %}
{% block body %}
<div id="pg-spinner" class="pg-sp-container">
<div class="pg-sp-content">
+50 -2
View File
@@ -22,6 +22,31 @@ from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost,\
CryptKeyMissing
def underscore_escape(text):
"""
This function mimics the behaviour of underscore js escape function
The html escaped by jinja is not compatible for underscore unescape
function
:param text: input html text
:return: escaped text
"""
html_map = {
'&': "&amp;",
'<': "&lt;",
'>': "&gt;",
'"': "&quot;",
'`': "&#96;",
"'": "&#x27;"
}
# always replace & first
for c, r in sorted(html_map.items(),
key=lambda x: 0 if x[0] == '&' else 1):
text = text.replace(c, r)
return text
def is_version_in_range(sversion, min_ver, max_ver):
assert (max_ver is None or isinstance(max_ver, int))
assert (min_ver is None or isinstance(min_ver, int))
@@ -461,10 +486,12 @@ class PGChildNodeView(NodeView):
'S': 'sequence',
'v': 'view',
'x': 'external_table',
'p': 'function',
'p': 'partition',
'P': 'function',
'n': 'schema',
'y': 'type',
'd': 'domain',
't': 'trigger_function',
'T': 'trigger',
'l': 'language',
'f': 'foreign_data_wrapper',
@@ -500,6 +527,7 @@ class PGChildNodeView(NodeView):
ref_name = nsp_name + '.'
type_name = ''
icon = None
# Fetch the type name from the dictionary
# if type is not present in the types dictionary then
@@ -514,6 +542,25 @@ class PGChildNodeView(NodeView):
type_name = 'column'
else:
type_name = 'table'
if 'is_inherits' in row \
and row['is_inherits'] == '1':
if 'is_inherited' in row \
and row['is_inherited'] == '1':
icon = 'icon-table-multi-inherit'
# For tables under partitioned tables,
# is_inherits will be true and dependency
# will be auto as it inherits from parent
# partitioned table
elif ('is_inherited' in row and
row['is_inherited'] == '0')\
and dep_str == 'a':
type_name = 'partition'
else:
icon = 'icon-table-inherits'
elif 'is_inherited' in row \
and row['is_inherited'] == '1':
icon = 'icon-table-inherited'
elif type_str[0] == 'R':
type_name = 'rule'
ref_name = \
@@ -569,7 +616,8 @@ class PGChildNodeView(NodeView):
{
'type': type_name,
'name': ref_name,
'field': dep_type
'field': dep_type,
'icon': icon,
}
)
@@ -70,7 +70,8 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='Query Tool']").click()
".wcFrameButton[title='Query Tool']:not(.disabled)")\
.click()
break
except StaleElementReferenceException:
retry_count += 1
@@ -89,7 +90,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='View Data']").click()
".wcFrameButton[title='View Data']:not(.disabled)").click()
break
except StaleElementReferenceException:
retry_count += 1
@@ -102,12 +103,13 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='Filtered Rows']").click()
".wcFrameButton[title='Filtered Rows']:not(.disabled)")\
.click()
break
except StaleElementReferenceException:
retry_count += 1
time.sleep(0.5)
self.page.find_by_css_selector(
".alertify .ajs-header[data-title='Data Filter']")
".alertify .ajs-header[data-title~='Filter']")
self.page.click_modal('Cancel')
@@ -117,10 +117,10 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
iteration = 0
success = False
while not success and iteration < 4:
self.page.find_by_xpath("//th[@data-column='0']"
"/div/span[text()='Name']").click()
# Check for sort Ascending
try:
self.page.find_by_xpath("//th[@data-column='0']"
"/div/span[text()='Name']").click()
self.wait.until(
EC.presence_of_element_located((
By.CSS_SELECTOR,
@@ -161,6 +161,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
os.remove(backup_file)
def after(self):
test_gui_helper.close_bgprocess_popup(self)
self.page.remove_server(self.server)
connection = test_utils.get_db_connection(
self.server['db'],
@@ -116,6 +116,7 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
"div.wcFloatingFocus div.fa-close").click()
def after(self):
test_gui_helper.close_bgprocess_popup(self)
self.page.remove_server(self.server)
connection = test_utils.get_db_connection(
self.server['db'],
@@ -36,7 +36,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
def before(self):
test_utils.create_table(
self.server, self.test_db, self.test_table_name
self.server, self.test_db, self.test_table_name,
['"<script>alert(1)</script>" char']
)
# This is needed to test dependents tab (eg: BackGrid)
test_utils.create_constraint(
@@ -63,8 +64,14 @@ class CheckForXssFeatureTest(BaseFeatureTest):
# Query tool
self.page.open_query_tool()
self._check_xss_in_query_tool()
self._check_xss_in_query_tool_history()
self.page.close_query_tool()
# Query tool view/edit data
self.page.open_view_data(self.test_table_name)
self._check_xss_view_data()
self.page.close_data_grid()
# Explain module
self.page.open_query_tool()
self._check_xss_in_explain_module()
@@ -177,6 +184,81 @@ class CheckForXssFeatureTest(BaseFeatureTest):
"Query tool (SlickGrid)"
)
def _check_xss_in_query_tool_history(self):
print(
"\n\tChecking the query tool history for the XSS",
file=sys.stderr, end=""
)
self.page.fill_codemirror_area_with(
"select '<script>alert(1)</script>"
)
self.page.find_by_id("btn-flash").click()
self.page.click_tab('Query History')
# Check for history entry
history_ele = self.page.find_by_css_selector(
".query-history div.query-group:first-child"
" .list-item.selected .query"
)
source_code = history_ele.get_attribute('innerHTML')
self._check_escaped_characters(
source_code,
'&lt;script&gt;alert(1)&lt;/script&gt;',
"Query tool (History Entry)"
)
# Check for history details message
history_ele = self.page.find_by_css_selector(
".query-detail .content-value"
)
source_code = history_ele.get_attribute('innerHTML')
self._check_escaped_characters(
source_code,
'&lt;script&gt;alert(1)&lt;/script&gt;',
"Query tool (History Details-Message)"
)
# Check for history details error message
history_ele = self.page.find_by_css_selector(
".query-detail .history-error-text"
)
source_code = history_ele.get_attribute('innerHTML')
self._check_escaped_characters(
source_code,
'&lt;script&gt;alert(1)&lt;/script&gt;',
"Query tool (History Details-Error)"
)
self.page.click_tab('Query Editor')
def _check_xss_view_data(self):
print(
"\n\tChecking the SlickGrid cell for the XSS",
file=sys.stderr, end=""
)
self.page.find_by_css_selector(".slick-header-column")
cells = self.driver.\
find_elements_by_css_selector(".slick-header-column")
# remove first element as it is row number.
# currently 4th col
source_code = cells[4].get_attribute('innerHTML')
self._check_escaped_characters(
source_code,
'&lt;script&gt;alert(1)&lt;/script&gt;',
"View Data (SlickGrid)"
)
def _check_xss_in_explain_module(self):
print(
"\n\tChecking the Graphical Explain plan for the XSS ...",
@@ -7,6 +7,8 @@
#
##########################################################################
import random
from selenium.webdriver import ActionChains
from selenium.common.exceptions import TimeoutException
from regression.python_test_utils import test_utils
@@ -22,6 +24,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
scenarios = [
("Tests to check if Debugger is vulnerable to XSS", dict())
]
function_name = ""
def before(self):
with test_utils.Database(self.server) as (connection, _):
@@ -32,12 +35,14 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
)
# Some test function is needed for debugger
self.function_name = "a_test_function" + \
str(random.randint(10000, 65535))
test_utils.create_debug_function(
self.server, "postgres", "a_test_function"
self.server, "postgres", self.function_name
)
if test_utils.does_function_exist(self.server, 'postgres',
'a_test_function') != 'True':
self.function_name) != 'True':
raise Exception("The required function is not found")
def runTest(self):
@@ -49,7 +54,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
def after(self):
self.page.remove_server(self.server)
test_utils.drop_debug_function(self.server, "postgres",
"a_test_function")
self.function_name)
def _function_node_expandable(self):
self.page.toggle_open_server(self.server['name'])
@@ -58,7 +63,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
self.page.toggle_open_tree_item('Schemas')
self.page.toggle_open_tree_item('public')
self.page.toggle_open_function_node()
self.page.select_tree_item("a_test_function()")
self.page.select_tree_item(self.function_name + "()")
def _debug_function(self):
self.page.driver.find_element_by_link_text("Object").click()
+586 -565
View File
File diff suppressed because it is too large. Load diff
@@ -46,10 +46,12 @@ define('misc.dependencies', [
// This function is used to fetch/set the icon for the type(Function, Role, Database, ....)
parse: function(res) {
var node = pgBrowser.Nodes[res.type];
res.icon = node ? (_.isFunction(node['node_image']) ?
(node['node_image']).apply(node, [null, null]) :
(node['node_image'] || ('icon-' + res.type))) :
('icon-' + res.type);
if(res.icon == null || res.icon == '') {
res.icon = node ? (_.isFunction(node['node_image']) ?
(node['node_image']).apply(node, [null, null]) :
(node['node_image'] || ('icon-' + res.type))) :
('icon-' + res.type);
}
res.type = S.titleize(res.type.replace(/_/g, ' '), true);
return res;
},
@@ -46,10 +46,12 @@ define('misc.dependents', [
// This function is used to fetch/set the icon for the type(Function, Role, Database, ....)
parse: function(res) {
var node = pgBrowser.Nodes[res.type];
res.icon = node ? (_.isFunction(node['node_image']) ?
(node['node_image']).apply(node, [null, null]) :
(node['node_image'] || ('icon-' + res.type))) :
('icon-' + res.type);
if(res.icon == null || res.icon == '') {
res.icon = node ? (_.isFunction(node['node_image']) ?
(node['node_image']).apply(node, [null, null]) :
(node['node_image'] || ('icon-' + res.type))) :
('icon-' + res.type);
}
res.type = S.titleize(res.type.replace(/_/g, ' '), true);
return res;
},
@@ -1466,9 +1466,14 @@ define([
'<a href="javascript:void(0);" class="fa fa-trash dz_file_remove" data-dz-remove></a>' +
'</div>';
// We need to append our csrf token with dropzone's ajax request header
let csrfToken = {};
csrfToken[pgAdmin.csrf_token_header] = pgAdmin.csrf_token;
$('div#multiple-uploads').dropzone({
paramName: 'newfile',
url: pgAdmin.FileUtils.fileConnector,
headers: csrfToken,
maxFilesize: fileSize,
maxFiles: config.upload.number,
addRemoveLinks: true,
@@ -5,7 +5,7 @@ SELECT nsp.nspname schema_name,
att.attname column_name,
att.atttypid::regtype::text type_name,
att.atthasdef AS has_default,
def.adsrc as default
pg_get_expr(def.adbin, def.adrelid) as default
FROM pg_catalog.pg_attribute att
INNER JOIN pg_catalog.pg_class cls
ON att.attrelid = cls.oid
@@ -26,7 +26,7 @@ SELECT nsp.nspname schema_name,
att.attname column_name,
att.atttypid::regtype::text type_name,
att.atthasdef AS has_default,
def.adsrc as default
pg_get_expr(def.adbin, def.adrelid) as default
FROM pg_catalog.pg_attribute att
INNER JOIN pg_catalog.pg_class cls
ON att.attrelid = cls.oid
@@ -266,6 +266,17 @@ define([
this.set('onresized', alertifyDialogResized.bind(this, true));
this.set('onmaximized', alertifyDialogResized);
this.set('onrestored', alertifyDialogResized);
/* Set the key to null if it is not defined
* When Browser autofill drop down value is clicked it raises a keyup event
* with undefined keyCode. The undefined keyCode matches the undefined key
* of alertify and triggers the button
*/
for(let i=0; i<this.__internal.buttons.length; i++) {
if(_.isUndefined(this.__internal.buttons[i]['key'])) {
this.__internal.buttons[i]['key'] = null;
}
}
};
alertify.pgHandleItemError = function(xhr, error, message, args) {
+66 -41
View File
@@ -9,6 +9,7 @@
import $ from 'jquery';
import gettext from 'sources/gettext';
import { getMod } from 'sources/utils';
const PERIOD_KEY = 190,
FWD_SLASH_KEY = 191,
@@ -116,9 +117,52 @@ function validateShortcutKeys(user_defined_shortcut, event) {
user_defined_shortcut.key.key_code == keyCode;
}
// Finds the desired panel on which user wants to navigate to
function focusDockerPanel(docker, op) {
if(!docker) {
return;
}
// If no frame in focus, focus the first one
if(!docker._focusFrame) {
if(docker._frameList.length == 0 && docker._frameList[0]._panelList.length == 0) {
return;
}
docker._frameList[0]._panelList[docker._frameList[0]._curTab].focus();
}
let focus_frame = docker._focusFrame,
focus_id = 0,
flash = false;
// Mod is used to cycle the op
if (op == 'switch') {
let i = 0, total_frames = docker._frameList.length;
for(i = 0; i < total_frames; i++) {
if(focus_frame === docker._frameList[i]) break;
}
focus_frame = docker._frameList[getMod(i+1,total_frames)];
focus_id = focus_frame._curTab;
flash = true;
} else if (op == 'left') {
focus_id = getMod(focus_frame._curTab-1, focus_frame._panelList.length);
flash = false;
} else if (op == 'right') {
focus_id = getMod(focus_frame._curTab+1, focus_frame._panelList.length);
flash = false;
}
let focus_panel = focus_frame._panelList[focus_id];
focus_panel.$container.find('*[tabindex]:not([tabindex="-1"])').trigger('focus');
focus_panel.focus(flash);
return focus_panel._type;
}
/* Debugger: Keyboard Shortcuts handling */
function keyboardShortcutsDebugger($el, event, preferences) {
let panel_id, panel_content, $input;
function keyboardShortcutsDebugger($el, event, preferences, docker) {
let panel_type = '', panel_content, $input;
if(this.validateShortcutKeys(preferences.edit_grid_values, event)) {
this._stopEventPropagation(event);
@@ -132,54 +176,32 @@ function keyboardShortcutsDebugger($el, event, preferences) {
}
} else if(this.validateShortcutKeys(preferences.move_next, event)) {
this._stopEventPropagation(event);
panel_id = this.getInnerPanel($el, 'right');
panel_type = focusDockerPanel(docker, 'right');
} else if(this.validateShortcutKeys(preferences.move_previous, event)) {
this._stopEventPropagation(event);
panel_id = this.getInnerPanel($el, 'left');
panel_type = focusDockerPanel(docker, 'left');
} else if(this.validateShortcutKeys(preferences.switch_panel, event)) {
this._stopEventPropagation(event);
panel_type = focusDockerPanel(docker, 'switch');
}
return panel_id;
}
// Finds the desired panel on which user wants to navigate to
function getInnerPanel($el, direction) {
if(!$el || !$el.length)
return false;
let total_panels = $el.find('.wcPanelTab');
// If no panels found OR if single panel
if (!total_panels.length || total_panels.length == 1)
return false;
let active_panel = $(total_panels).filter('.wcPanelTabActive'),
id = parseInt($(active_panel).attr('id')),
fist_panel = 0,
last_panel = total_panels.length - 1;
// Find desired panel
if (direction == 'left') {
if(id > fist_panel)
id--;
} else {
if (id < last_panel)
id++;
}
return id;
return panel_type;
}
/* Query tool: Keyboard Shortcuts handling */
function keyboardShortcutsQueryTool(
sqlEditorController, queryToolActions, event
sqlEditorController, queryToolActions, event, docker
) {
if (sqlEditorController.isQueryRunning()) {
return;
}
let keyCode = event.which || event.keyCode, panel_id;
let keyCode = event.which || event.keyCode, panel_type = '';
let executeKeys = sqlEditorController.preferences.execute_query;
let explainKeys = sqlEditorController.preferences.explain_query;
let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query;
let downloadCsvKeys = sqlEditorController.preferences.download_csv;
let nextPanelKeys = sqlEditorController.preferences.move_next;
let previousPanelKeys = sqlEditorController.preferences.move_previous;
let nextTabKeys = sqlEditorController.preferences.move_next;
let previousTabKeys = sqlEditorController.preferences.move_previous;
let switchPanelKeys = sqlEditorController.preferences.switch_panel;
let toggleCaseKeys = sqlEditorController.preferences.toggle_case;
let commitKeys = sqlEditorController.preferences.commit_transaction;
let rollbackKeys = sqlEditorController.preferences.rollback_transaction;
@@ -236,12 +258,15 @@ function keyboardShortcutsQueryTool(
&& $(event.target).closest('.dropdown-submenu').length > 0) {
$(event.target).closest('.dropdown-submenu').find('.dropdown-menu').removeClass('show');
}
} else if(this.validateShortcutKeys(nextPanelKeys, event)) {
} else if(this.validateShortcutKeys(nextTabKeys, event)) {
this._stopEventPropagation(event);
panel_id = this.getInnerPanel(sqlEditorController.container, 'right');
} else if(this.validateShortcutKeys(previousPanelKeys, event)) {
panel_type = focusDockerPanel(docker, 'right');
} else if(this.validateShortcutKeys(previousTabKeys, event)) {
this._stopEventPropagation(event);
panel_id = this.getInnerPanel(sqlEditorController.container, 'left');
panel_type = focusDockerPanel(docker, 'left');
} else if(this.validateShortcutKeys(switchPanelKeys, event)) {
this._stopEventPropagation(event);
panel_type = focusDockerPanel(docker, 'switch');
} else if(keyCode === UP_KEY || keyCode === DOWN_KEY) {
/*Apply only for dropdown*/
if($(event.target).closest('.dropdown-menu').length > 0) {
@@ -293,13 +318,13 @@ function keyboardShortcutsQueryTool(
}
}
return panel_id;
return panel_type;
}
export {
keyboardShortcutsDebugger as processEventDebugger,
keyboardShortcutsQueryTool as processEventQueryTool,
getInnerPanel, validateShortcutKeys,
focusDockerPanel, validateShortcutKeys,
_stopEventPropagation, isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
isKeyCtrlAltShift, isAltShiftBoth, isCtrlShiftBoth, isCtrlAltBoth,
shortcut_key, shortcut_title, shortcut_accesskey_title,
@@ -45,6 +45,8 @@ let GeometryViewer = {
geometry_viewer_panel.on(wcDocker.EVENT.VISIBILITY_CHANGED, function (visible) {
if (visible) {
self.map_component.resizeMap();
} else {
self.map_component.loseFocus();
}
});
}
@@ -186,6 +188,10 @@ function initMapComponent() {
vectorLayer.clearLayers();
},
'loseFocus': function() {
lmap.fire('blur');
},
'renderMap': function (dataObj) {
let geoJSONs = dataObj.geoJSONs,
SRID = dataObj.selectedSRID,
@@ -117,7 +117,7 @@ export default class QueryHistoryDetails {
updateMessageContent() {
this.$message_content
.empty()
.append(`<pre class='content-value'>${this.entry.message}</pre>`);
.append(`<pre class='content-value'>${_.escape(this.entry.message)}</pre>`);
}
updateErrorMessage() {
@@ -125,10 +125,8 @@ export default class QueryHistoryDetails {
this.$errMsgBlock.removeClass('d-none');
this.$errMsgBlock.empty().append(
`<div class='history-error-text'>
<span>Error Message</span> ${this.parseErrorMessage(
this.entry.message
)}
</div>`
<span>Error Message</span> ${_.escape(this.parseErrorMessage(this.entry.message))}
</div>`
);
} else {
this.$errMsgBlock.addClass('d-none');
@@ -1,5 +1,6 @@
import moment from 'moment';
import $ from 'jquery';
import _ from 'underscore';
const ARROWUP = 38;
const ARROWDOWN = 40;
@@ -68,7 +69,7 @@ export class QueryHistoryItem {
this.$el = $(
`<li class='list-item' tabindex='0' data-key='${this.dataKey()}'>
<div class='entry ${this.entry.status ? '' : 'error'}'>
<div class='query'>${this.entry.query}</div>
<div class='query'>${_.escape(this.entry.query)}</div>
<div class='other-info'>
<div class='timestamp'>${this.formatDate(this.entry.start_time)}</div>
</div>
+4
View File
@@ -79,3 +79,7 @@ export function getGCD(inp_arr) {
return result;
}
export function getMod(no, divisor) {
return ((no % divisor) + divisor) % divisor;
}
@@ -11,6 +11,7 @@
color: $color-primary-fg;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
border-radius: 0rem;
border-top-left-radius: $panel-border-radius;
border-top-right-radius: $panel-border-radius;
@@ -968,3 +968,18 @@ table.table-empty-rows{
bottom: 0;
}
}
.filter-textarea {
height: 100%;
& .CodeMirror-scroll {
min-height: 120px;
max-height: 120px;
}
}
.dataview_filter_dialog {
left: 0 !important;
right: 0 !important;
padding: 0px !important;
position: absolute;
}
-1
View File
@@ -20,7 +20,6 @@
<!-- Base template stylesheets -->
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='vendor/backgrid/backgrid.css')}}"/>
<link type="text/css" rel="stylesheet" href="{{ url_for('browser.browser_css')}}"/>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='js/generated/style.css')}}"/>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='js/generated/pgadmin.css')}}"/>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/alertify.noanimation.css')}}" id="alertify-no-animation"/>
@@ -27,6 +27,14 @@ export class BackupDialogWrapper extends DialogWrapper {
}
setup() {
let get_help_file = function (dialog_type) {
if (dialog_type == 'globals') {
return 'backup_globals_dialog.html';
} else if (dialog_type == 'server') {
return 'backup_server_dialog.html';
}
return 'backup_dialog.html';
};
return {
buttons: [{
text: '',
@@ -46,7 +54,7 @@ export class BackupDialogWrapper extends DialogWrapper {
type: 'button',
label: gettext('Backup'),
url: url_for('help.static', {
'filename': 'backup_dialog.html',
'filename': get_help_file(this.typeOfDialog),
}),
},
}, {
+3 -1
View File
@@ -30,6 +30,8 @@ from pgadmin.utils.driver import get_driver
from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
from pgadmin.utils.preferences import Preferences
from pgadmin.settings import get_setting
from pgadmin.browser.utils import underscore_escape
query_tool_close_session_lock = Lock()
@@ -304,7 +306,7 @@ def panel(trans_id, is_query_tool, editor_title):
_=gettext,
uniqueId=trans_id,
is_query_tool=is_query_tool,
editor_title=editor_title,
editor_title=underscore_escape(editor_title),
script_type_url=sURL,
is_desktop_mode=app.PGADMIN_RUNTIME,
is_linux=is_linux_platform,
@@ -12,18 +12,16 @@ define('pgadmin.datagrid', [
'pgadmin.alertifyjs', 'sources/pgadmin', 'bundled_codemirror',
'sources/sqleditor_utils', 'backbone',
'tools/datagrid/static/js/show_data',
'tools/datagrid/static/js/get_panel_title',
'tools/datagrid/static/js/show_query_tool', 'pgadmin.browser.toolbar',
'wcdocker',
'tools/datagrid/static/js/datagrid_panel_title', 'wcdocker',
], function(
gettext, url_for, $, _, alertify, pgAdmin, codemirror, sqlEditorUtils,
Backbone, showData, panelTitle, showQueryTool, toolBar
Backbone, showData, showQueryTool, toolBar, panelTitleFunc
) {
// Some scripts do export their object in the window only.
// Generally the one, which do no have AMD support.
var wcDocker = window.wcDocker,
pgBrowser = pgAdmin.Browser,
CodeMirror = codemirror.default;
pgBrowser = pgAdmin.Browser;
/* Return back, this has been called more than once */
if (pgAdmin.DataGrid)
@@ -202,188 +200,14 @@ define('pgadmin.datagrid', [
// This is a callback function to show filtered data when user click on menu item.
show_filtered_row: function(data, i) {
var self = this,
d = pgAdmin.Browser.tree.itemData(i);
if (d === undefined) {
alertify.alert(
gettext('Data Grid Error'),
gettext('No object selected.')
);
return;
}
// Get the parent data from the tree node hierarchy.
var node = pgBrowser.Nodes[d._type],
parentData = node.getTreeNodeHierarchy(i);
// If server or database is undefined then return from the function.
if (parentData.server === undefined || parentData.database === undefined) {
return;
}
// If schema, view, catalog object all are undefined then return from the function.
if (parentData.schema === undefined && parentData.view === undefined &&
parentData.catalog === undefined) {
return;
}
let nsp_name = showData.retrieveNameSpaceName(parentData);
var url_params = {
'cmd_type': data.mnuid,
'obj_type': d._type,
'sgid': parentData.server_group._id,
'sid': parentData.server._id,
'did': parentData.database._id,
'obj_id': d._id,
};
var baseUrl = url_for('datagrid.initialize_datagrid', url_params);
// Create url to validate the SQL filter
var validateUrl = url_for('datagrid.filter_validate', {
'sid': url_params['sid'],
'did': url_params['did'],
'obj_id': url_params['obj_id'],
});
let grid_title = showData.generateDatagridTitle(parentData, nsp_name, d);
// Create filter dialog using alertify
if (!alertify.filterDialog) {
alertify.dialog('filterDialog', function factory() {
return {
main: function(title, message, baseUrl, validateUrl) {
this.set('title', title);
this.message = message;
this.baseUrl = baseUrl;
this.validateUrl = validateUrl;
},
setup:function() {
return {
buttons:[{
text: gettext('Cancel'),
key: 27,
className: 'btn btn-secondary fa fa-times pg-alertify-button',
},{
text: gettext('OK'),
key: 13,
className: 'btn btn-primary fa fa-check pg-alertify-button',
}],
options: {
modal: 0,
resizable: true,
maximizable: false,
pinnable: false,
autoReset: false,
},
};
},
build: function() {
alertify.pgDialogBuild.apply(this);
},
prepare:function() {
var that = this,
$content = $(this.message),
$sql_filter = $content.find('#sql_filter');
$(this.elements.header).attr('data-title', this.get('title'));
$(this.elements.body.childNodes[0]).addClass(
'dataview_filter_dialog'
);
this.setContent($content.get(0));
// Disable OK button
that.__internal.buttons[1].element.disabled = true;
// Apply CodeMirror to filter text area.
this.filter_obj = CodeMirror.fromTextArea($sql_filter.get(0), {
lineNumbers: true,
mode: 'text/x-pgsql',
extraKeys: pgBrowser.editor_shortcut_keys,
indentWithTabs: !self.preferences.use_spaces,
indentUnit: self.preferences.tab_size,
tabSize: self.preferences.tab_size,
lineWrapping: self.preferences.wrap_code,
autoCloseBrackets: self.preferences.insert_pair_brackets,
matchBrackets: self.preferences.brace_matching,
});
let sql_font_size = sqlEditorUtils.calcFontSize(self.preferences.sql_font_size);
$(this.filter_obj.getWrapperElement()).css('font-size', sql_font_size);
setTimeout(function() {
// Set focus on editor
that.filter_obj.refresh();
that.filter_obj.focus();
}, 500);
that.filter_obj.on('change', function() {
if (that.filter_obj.getValue() !== '') {
that.__internal.buttons[1].element.disabled = false;
} else {
that.__internal.buttons[1].element.disabled = true;
}
});
},
callback: function(closeEvent) {
if (closeEvent.button.text == gettext('OK')) {
var sql = this.filter_obj.getValue();
var that = this;
closeEvent.cancel = true; // Do not close dialog
// Make ajax call to include the filter by selection
$.ajax({
url: that.validateUrl,
method: 'POST',
async: false,
contentType: 'application/json',
data: JSON.stringify(sql),
})
.done(function(res) {
if (res.data.status) {
// Initialize the data grid.
self.create_transaction(that.baseUrl, null, 'false', parentData.server.server_type, '', grid_title, sql, false);
that.close(); // Close the dialog
}
else {
alertify.alert(
gettext('Validation Error'),
res.data.result
);
}
})
.fail(function(e) {
alertify.alert(
gettext('Validation Error'),
e
);
});
}
},
};
});
}
$.get(url_for('datagrid.filter'),
function(data) {
alertify.filterDialog('Data Filter', data, baseUrl, validateUrl)
.resizeTo(pgBrowser.stdW.sm,pgBrowser.stdH.sm);
}
);
showData.showDataGrid(this, pgBrowser, alertify, data, i, true, this.preferences);
},
get_panel_title: function() {
return panelTitle.getPanelTitle(pgBrowser);
},
// This is a callback function to show query tool when user click on menu item.
show_query_tool: function(url, aciTreeIdentifier, panelTitle) {
showQueryTool.showQueryTool(this, pgBrowser, alertify, url,
aciTreeIdentifier, panelTitle);
show_query_tool: function(url, aciTreeIdentifier) {
showQueryTool.showQueryTool(this, pgBrowser, alertify, url, aciTreeIdentifier);
},
create_transaction: function(baseUrl, target, is_query_tool, server_type, sURL, panel_title, sql_filter, recreate) {
var self = this;
target = target || self;
@@ -439,29 +263,7 @@ define('pgadmin.datagrid', [
launch_grid: function(trans_obj) {
var self = this,
panel_title = trans_obj.panel_title,
grid_title = self.get_panel_title(),
panel_icon = '',
panel_tooltip = '';
if (trans_obj.is_query_tool == 'false') {
// Edit grid titles
grid_title = panel_title + '/' + grid_title;
panel_tooltip = gettext('View/Edit Data - ') + grid_title;
panel_title = grid_title;
panel_icon = 'fa fa-table';
} else {
if (panel_title) {
// Script titles
panel_tooltip = panel_title.toUpperCase() + ' ' + gettext('Script - ') + grid_title;
panel_title = grid_title;
panel_icon = 'fa fa-file-text-o';
} else {
// Query tool titles
panel_tooltip = gettext('Query Tool - ') + grid_title;
panel_title = grid_title;
panel_icon = 'fa fa-bolt';
}
}
grid_title = trans_obj.panel_title;
// Open the panel if frame is initialized
let titileForURLObj = sqlEditorUtils.removeSlashInTheString(grid_title);
@@ -497,8 +299,7 @@ define('pgadmin.datagrid', [
var queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, propertiesPanel[0]);
// Set panel title and icon
queryToolPanel.title('<span title="'+panel_tooltip+'">'+panel_title+'</span>');
queryToolPanel.icon(panel_icon);
panelTitleFunc.setQueryToolDockerTitle(queryToolPanel, trans_obj.is_query_tool, panel_title);
queryToolPanel.focus();
// Listen on the panel closed event.
@@ -8,6 +8,7 @@
//////////////////////////////////////////////////////////////
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
import gettext from 'sources/gettext';
function getDatabaseLabel(parentData) {
return parentData.database ? parentData.database.label
@@ -18,8 +19,10 @@ function isServerInformationAvailable(parentData) {
return parentData.server === undefined;
}
export function getPanelTitle(pgBrowser) {
const selected_item = pgBrowser.treeMenu.selected();
export function getPanelTitle(pgBrowser, selected_item=null) {
if(selected_item == null) {
selected_item = pgBrowser.treeMenu.selected();
}
const parentData = getTreeNodeHierarchyFromIdentifier
.call(pgBrowser, selected_item);
@@ -31,3 +34,24 @@ export function getPanelTitle(pgBrowser) {
return `${db_label}/${parentData.server.user.name}@${parentData.server.label}`;
}
export function setQueryToolDockerTitle(panel, is_query_tool, panel_title, is_file) {
let panel_icon = '', panel_tooltip = '';
if(is_file || is_file == 'true'){
panel_tooltip = gettext('File - ') + panel_title;
panel_icon = 'fa fa-file-text-o';
}
else if (is_query_tool == 'false' || is_query_tool == false) {
// Edit grid titles
panel_tooltip = gettext('View/Edit Data - ') + panel_title;
panel_icon = 'fa fa-table';
} else {
// Query tool titles
panel_tooltip = gettext('Query Tool - ') + panel_title;
panel_icon = 'fa fa-bolt';
}
panel.title('<span title="'+_.escape(panel_tooltip)+'">'+_.escape(panel_title)+'</span>');
panel.icon(panel_icon);
}
+188 -14
View File
@@ -9,13 +9,19 @@
import gettext from '../../../../static/js/gettext';
import url_for from '../../../../static/js/url_for';
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
import {getPanelTitle} from './datagrid_panel_title';
import CodeMirror from 'bundled_codemirror';
import * as SqlEditorUtils from 'sources/sqleditor_utils';
import $ from 'jquery';
export function showDataGrid(
datagrid,
pgBrowser,
alertify,
connectionData,
aciTreeIdentifier
aciTreeIdentifier,
filter=false,
preferences=null
) {
const node = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
if (node === undefined || !node.getData()) {
@@ -36,19 +42,44 @@ export function showDataGrid(
return;
}
let namespaceName = retrieveNameSpaceName(parentData);
const baseUrl = generateUrl(connectionData, node.getData(), parentData);
const grid_title = generateDatagridTitle(parentData, namespaceName, node.getData());
const grid_title = generateDatagridTitle(pgBrowser, aciTreeIdentifier);
datagrid.create_transaction(
baseUrl,
null,
'false',
parentData.server.server_type,
'',
grid_title,
''
);
if(filter) {
initFilterDialog(alertify, pgBrowser, preferences);
const validateUrl = generateFilterValidateUrl(node.getData(), parentData);
let okCallback = function(sql) {
datagrid.create_transaction(
baseUrl,
null,
'false',
parentData.server.server_type,
'',
grid_title,
sql,
false
);
};
$.get(url_for('datagrid.filter'),
function(data) {
alertify.filterDialog(`Data Filter - ${grid_title}`, data, validateUrl, preferences, okCallback)
.resizeTo(pgBrowser.stdW.sm,pgBrowser.stdH.sm);
}
);
} else {
datagrid.create_transaction(
baseUrl,
null,
'false',
parentData.server.server_type,
'',
grid_title,
''
);
}
}
@@ -78,6 +109,138 @@ function generateUrl(connectionData, nodeData, parentData) {
return url_for('datagrid.initialize_datagrid', url_params);
}
function generateFilterValidateUrl(nodeData, parentData) {
// Create url to validate the SQL filter
var url_params = {
'sid': parentData.server._id,
'did': parentData.database._id,
'obj_id': nodeData._id,
};
return url_for('datagrid.filter_validate', url_params);
}
function initFilterDialog(alertify, pgBrowser) {
// Create filter dialog using alertify
if (!alertify.filterDialog) {
alertify.dialog('filterDialog', function factory() {
return {
main: function(title, message, validateUrl, preferences, okCallback) {
this.set('title', title);
this.message = message;
this.validateUrl = validateUrl;
this.okCallback = okCallback;
this.preferences = preferences;
},
setup:function() {
return {
buttons:[{
text: gettext('Cancel'),
key: 27,
className: 'btn btn-secondary fa fa-times pg-alertify-button',
},{
text: gettext('OK'),
key: 13,
className: 'btn btn-primary fa fa-check pg-alertify-button',
}],
options: {
modal: 0,
resizable: true,
maximizable: false,
pinnable: false,
autoReset: false,
},
};
},
build: function() {
alertify.pgDialogBuild.apply(this);
},
prepare:function() {
var that = this,
$content = $(this.message),
$sql_filter = $content.find('#sql_filter');
$(this.elements.header).attr('data-title', this.get('title'));
$(this.elements.body.childNodes[0]).addClass(
'dataview_filter_dialog'
);
this.setContent($content.get(0));
// Disable OK button
that.__internal.buttons[1].element.disabled = true;
// Apply CodeMirror to filter text area.
this.filter_obj = CodeMirror.fromTextArea($sql_filter.get(0), {
lineNumbers: true,
mode: 'text/x-pgsql',
extraKeys: pgBrowser.editor_shortcut_keys,
indentWithTabs: !that.preferences.use_spaces,
indentUnit: that.preferences.tab_size,
tabSize: that.preferences.tab_size,
lineWrapping: that.preferences.wrap_code,
autoCloseBrackets: that.preferences.insert_pair_brackets,
matchBrackets: that.preferences.brace_matching,
});
let sql_font_size = SqlEditorUtils.calcFontSize(that.preferences.sql_font_size);
$(this.filter_obj.getWrapperElement()).css('font-size', sql_font_size);
setTimeout(function() {
// Set focus on editor
that.filter_obj.refresh();
that.filter_obj.focus();
}, 500);
that.filter_obj.on('change', function() {
if (that.filter_obj.getValue() !== '') {
that.__internal.buttons[1].element.disabled = false;
} else {
that.__internal.buttons[1].element.disabled = true;
}
});
},
callback: function(closeEvent) {
if (closeEvent.button.text == gettext('OK')) {
var sql = this.filter_obj.getValue();
var that = this;
closeEvent.cancel = true; // Do not close dialog
// Make ajax call to include the filter by selection
$.ajax({
url: that.validateUrl,
method: 'POST',
async: false,
contentType: 'application/json',
data: JSON.stringify(sql),
})
.done(function(res) {
if (res.data.status) {
that.okCallback(sql);
that.close(); // Close the dialog
}
else {
alertify.alert(
gettext('Validation Error'),
res.data.result
);
}
})
.fail(function(e) {
alertify.alert(
gettext('Validation Error'),
e
);
});
}
},
};
});
}
}
function hasServerOrDatabaseConfiguration(parentData) {
return parentData.server === undefined || parentData.database === undefined;
}
@@ -87,6 +250,17 @@ function hasSchemaOrCatalogOrViewInformation(parentData) {
parentData.catalog !== undefined;
}
export function generateDatagridTitle(parentData, namespaceName, nodeData) {
return `${namespaceName}.${nodeData.label}`;
export function generateDatagridTitle(pgBrowser, aciTreeIdentifier) {
const baseTitle = getPanelTitle(pgBrowser, aciTreeIdentifier);
const parentData = getTreeNodeHierarchyFromIdentifier.call(
pgBrowser,
aciTreeIdentifier
);
const namespaceName = retrieveNameSpaceName(parentData);
const node = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
return `${namespaceName}.${node.getData().label}/${baseTitle}`;
}
@@ -10,6 +10,7 @@
import gettext from '../../../../static/js/gettext';
import url_for from '../../../../static/js/url_for';
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
import {getPanelTitle} from './datagrid_panel_title';
function hasDatabaseInformation(parentData) {
return parentData.database;
@@ -34,10 +35,14 @@ function hasServerInformations(parentData) {
return parentData.server === undefined;
}
export function showQueryTool(datagrid, pgBrowser, alertify, url,
aciTreeIdentifier, panelTitle) {
function generateTitle(pgBrowser, aciTreeIdentifier) {
const baseTitle = getPanelTitle(pgBrowser, aciTreeIdentifier);
return baseTitle;
}
export function showQueryTool(datagrid, pgBrowser, alertify, url, aciTreeIdentifier) {
const sURL = url || '';
const queryToolTitle = panelTitle || '';
const queryToolTitle = generateTitle(pgBrowser, aciTreeIdentifier);
const currentNode = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
if (currentNode === undefined) {
@@ -1,15 +1,3 @@
<div class="filter-textarea">
<textarea id="sql_filter" rows="5" tabindex="0"></textarea>
<style>
.filter-textarea .CodeMirror-scroll {
min-height: 120px;
max-height: 120px;
}
.dataview_filter_dialog {
left: 0 !important;
right: 0 !important;
padding: 0px !important;
position: absolute;
}
</style>
</div>
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff. Show more