mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-28 07:30:05 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
173acd46a5 | ||
|
|
c39d257bf6 | ||
|
|
b3490ba3de | ||
|
|
4e5d8fe8e2 | ||
|
|
c4de5474a4 | ||
|
|
ebb5e3fe65 | ||
|
|
644624eabe | ||
|
|
9dbb74367d | ||
|
|
c07e52b9de | ||
|
|
78d55c7cc0 | ||
|
|
81752bb998 | ||
|
|
fb4afce629 | ||
|
|
6e8ebbd375 | ||
|
|
5c0ea0c012 | ||
|
|
ce7679c4bd | ||
|
|
b36d5d153b | ||
|
|
9e65c971a3 | ||
|
|
71919a4ce9 | ||
|
|
402dfd07db | ||
|
|
bf548dda3f | ||
|
|
2894c6cd14 | ||
|
|
3b69f92d70 | ||
|
|
82bd94e696 | ||
|
|
04328b76ba | ||
|
|
08b78fb6a1 | ||
|
|
23364464c2 | ||
|
|
d774a0ff67 | ||
|
|
5437a8adab | ||
|
|
6d52f2b911 | ||
|
|
2ca11c84e8 | ||
|
|
f561c0cee6 | ||
|
|
321b445a7e | ||
|
|
7ff85903e4 | ||
|
|
8b9c50ee5c | ||
|
|
4b6e9b031c | ||
|
|
e691885881 | ||
|
|
caf181d5e3 | ||
|
|
d90136d93d | ||
|
|
9a00a8a60b | ||
|
|
a588c2994d | ||
|
|
13704a4f34 | ||
|
|
912db8913f |
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
**********
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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,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
@@ -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
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
+9
@@ -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';
|
||||
+7
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-2
@@ -11,6 +11,5 @@ from pgadmin.utils.route import BaseTestGenerator
|
||||
|
||||
|
||||
class CollationTestGenerator(BaseTestGenerator):
|
||||
|
||||
def generate_tests(self):
|
||||
def runTest(self):
|
||||
return
|
||||
+3
-1
@@ -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}
|
||||
|
||||
|
||||
+8
@@ -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;
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+2
-1
@@ -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}}
|
||||
|
||||
+1
-2
@@ -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):
|
||||
"""
|
||||
|
||||
+2
-2
@@ -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
|
||||
+2
@@ -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'))) {
|
||||
|
||||
|
||||
+38
-22
@@ -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))
|
||||
|
||||
+1
@@ -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 |
+1
@@ -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 |
+1
@@ -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 |
+30
-2
@@ -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'],
|
||||
|
||||
+1
-1
@@ -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 %}
|
||||
|
||||
+1
-1
@@ -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 %}
|
||||
|
||||
+83
@@ -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;
|
||||
+83
@@ -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;
|
||||
+1
-1
@@ -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 %}
|
||||
|
||||
+3
-1
@@ -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
|
||||
|
||||
+182
@@ -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)}}
|
||||
+8
@@ -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
|
||||
+75
@@ -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;
|
||||
+211
@@ -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 %}
|
||||
+3
-1
@@ -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 %}
|
||||
|
||||
+1
-1
@@ -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 %}
|
||||
|
||||
+3
-1
@@ -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 %}
|
||||
|
||||
+1
-1
@@ -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 %}
|
||||
|
||||
+3
-1
@@ -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)
|
||||
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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
|
||||
)
|
||||
+4
-8
@@ -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(
|
||||
|
||||
+1
-1
@@ -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?'),
|
||||
|
||||
+51
@@ -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
|
||||
+50
@@ -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
|
||||
+10
-4
@@ -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
|
||||
+9
-3
@@ -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',
|
||||
|
||||
+10
-4
@@ -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
|
||||
+9
-3
@@ -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)
|
||||
@@ -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">
|
||||
|
||||
@@ -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 = {
|
||||
'&': "&",
|
||||
'<': "<",
|
||||
'>': ">",
|
||||
'"': """,
|
||||
'`': "`",
|
||||
"'": "'"
|
||||
}
|
||||
|
||||
# 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,
|
||||
'<script>alert(1)</script>',
|
||||
"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,
|
||||
'<script>alert(1)</script>',
|
||||
"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,
|
||||
'<script>alert(1)</script>',
|
||||
"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,
|
||||
'<script>alert(1)</script>',
|
||||
"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
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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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),
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
|
||||
@@ -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.
|
||||
|
||||
+26
-2
@@ -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);
|
||||
}
|
||||
@@ -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
Reference in new issue
Block a user