Compare commits

...
45 Commits
Author SHA1 Message Date
Khushboo Vashi cc38bc132e Fixed scroll issue in the browser tree when navigating using the keyboard. 2021-11-15 18:26:16 +05:30
Akshay Joshi 053519aef6 Update version for release. 2021-11-15 16:38:10 +05:30
Nikhil Mohite 1408bad8ba Fixed an issue where reset layout message showing when the user opens the query tool.
refs #6988
2021-11-15 16:34:25 +05:30
Pradip Parkale 33cc2a7514 Fixed an issue where SQL for index shows the same column multiple times. Fixes #6981 2021-11-15 16:31:40 +05:30
Domenico Sgarbossa d6a754e850 Update Italian translation. 2021-11-15 12:56:58 +05:30
Libor M fc05ef49ce Update Czech translation. 2021-11-15 12:54:06 +05:30
Identifier Anonymous b36a290b54 Update Japanese translation. 2021-11-15 12:52:09 +05:30
Akshay Joshi 0ca7dbccf6 Ensure that the Binary path for PG14 should be visible in the preferences. Fixes #6972 2021-11-15 12:44:33 +05:30
Khushboo Vashi e67bad3461 Ensure that the user should be able to navigate browser tree objects using arrow keys from keyboard. Fixes #6896 2021-11-15 11:17:42 +05:30
Yogesh Mahajan e2e5a8208c 1) Fixed an issue where JSON editor preview colours have inappropriate contrast in dark mode. Fixes #6944
2) Fixed JSON Editor scrolling issue in code mode. Fixes #6945
2021-11-15 10:58:17 +05:30
Akshay Joshi a47cbbe26c Update Dependencies. 2021-11-12 20:02:51 +05:30
Akshay Joshi 59707fc8af Update message catalogs. 2021-11-12 20:01:25 +05:30
Akshay Joshi 25ace94d10 Fixed API test cases for search object. 2021-11-12 19:58:29 +05:30
Akshay Joshi ca4d5d0ca4 Added operators and aggregates in search objects. Fixes #6974 2021-11-12 17:45:08 +05:30
Aditya Toshniwal 600690a789 Fixed JS audit issues. 2021-11-12 14:19:09 +05:30
Yogesh Mahajan 77931d2315 Uses selenium 4.0.0a6 which works with python 3.6 2021-11-12 11:56:44 +05:30
Nikhil Mohite 8bf178b0a3 Reset the layout if pgAdmin4 detects the layout is in an inconsistent state. Fixes #6988 2021-11-12 11:50:37 +05:30
Pradip Parkale d4bf7164f9 Ensure that inherit table icon should be visible properly in the tree view. Fixes #6845 2021-11-11 12:55:38 +05:30
Nikhil Mohite 7468ca36ae Fixed SQL syntax error if select "Custom auto-vacuum" option and not set Autovacuum option to Yes or No. Fixes #6925 2021-11-11 12:36:19 +05:30
Rahul Shirsat 572b5a126a Ensure that internal authentication when combined with other authentication providers, the order of internal source should not matter while picking up the provider. Fixes #6832 2021-11-11 12:29:30 +05:30
Akshay Joshi 36e5708464 Correct the release notes. 2021-11-10 15:44:03 +05:30
Khushboo Vashi d4697e8f1c Ensure that users should be able to modify the REMOTE_USER environment
variable as per their environment by introducing the new config parameter
WEBSERVER_REMOTE_USER.

Fixes #6953
2021-11-10 15:38:41 +05:30
Yogesh Mahajan 9479f0e632 Fixed feature test cases after react porting. 2021-11-10 11:50:20 +05:30
Khushboo Vashi aff84103d9 Fixed an issue where database nodes are not getting loaded behind a reverse
proxy with SSL. Fixes #6905
2021-11-10 11:47:40 +05:30
Pradip Parkale a61a9e5b8f Fixed an issue where older server group name displayed in the confirmation
pop-up when the user removes server group. Fixes #6939
2021-11-10 11:17:51 +05:30
Pradip Parkale eb8168285e Cover more scenarios for the pgAdmin freezing issue. Fixes #5427 2021-11-10 11:11:24 +05:30
Aditya Toshniwal 1ed4d0f95e Fixed an issue where textarea should be allowed to resize and have more than 255 chars. Fixes #6976 2021-11-07 10:51:54 +05:30
Aditya Toshniwal 31849ea95f Ensure that changing themes should work on Windows when system high contrast
mode is enabled. Fixes #6954
2021-11-07 10:46:49 +05:30
Dave Page d7f5e13cdd Revert changes to support Python 3.10. Too many things broke, needs more thought :-( 2021-11-03 14:50:05 +00:00
Dave Page 33aeacd8d1 Only include the dnspython library for Python 3.10. 2021-11-03 13:20:09 +00:00
Dave Page f3bf068066 Fix dependencies to work with Python 3.10.
Patch by me, legwork by Aditya.
2021-11-03 13:12:11 +00:00
Akshay Joshi 719f8c8fd2 Fixed API test case for DataTypeReader 2021-10-29 17:37:02 +05:30
Pradip Parkale fa8b3edda5 Fixed an issue where user details are not shown when the non-admin user tries
to connect to the shared server. Fixes #6940
2021-10-29 16:26:11 +05:30
Nikhil Mohite f71e2e8040 Fixed an issue where pgAdmin is not opening properly. Fixes #6809 2021-10-29 16:17:36 +05:30
Akshay Joshi 39992a817d Added support of Aggregate and Operator node in view-only mode. Fixes #3834 2021-10-29 16:14:33 +05:30
Akshay Joshi 7b85253465 Corrected some menu lables. 2021-10-27 11:05:23 +05:30
Pradip Parkale 35b1e1d0d2 Fixed pgAdmin freezing issue by providing the error message for the operation
that can't perform due to lock on the particular table. Fixes #5427
2021-10-27 10:51:52 +05:30
Rahul Shirsat 711ea3bfa1 Fixed an issue where properties panel is not updated when any object is added from the browser tree. Fixes #6859 2021-10-27 10:31:49 +05:30
Rahul Shirsat 8eb6f8061d Ensure that dialog should be opened when clicking on Reassign/Drop owned menu. Fixes #6949 2021-10-25 11:47:28 +05:30
Akshay Joshi 2c4ed4d115 Reverted the last patch to pin mozjpeg as it didn't work. 2021-10-21 17:06:04 +05:30
Aditya Toshniwal fc233ed993 Pin mozjpeg to 7.1.0 as the latest version will require zlib to be re-compiled. 2021-10-21 16:18:06 +05:30
Aditya Toshniwal 1d8810775c Fixed JS audit issues wherever possible and ignores devDependencies from packages.json 2021-10-21 15:08:24 +05:30
Aditya Toshniwal d28e249673 Ignore flask-security-too irrelevant vulnerability. 2021-10-21 11:14:27 +05:30
Pradip Parkale c7cd57db91 Ensure that columns should be merged if the newly added column is present in the parent table. Fixes #6780 2021-10-21 10:59:52 +05:30
Akshay Joshi d2a7f7fffe Fixed API test cases for PG 14 2021-10-20 18:39:42 +05:30
141 changed files with 21301 additions and 15333 deletions

No files matched your search

+170 -67
View File
@@ -29,34 +29,34 @@ Flask-Login 0.5.0
Flask-Mail 0.9.1 BSD https://github.com/rduplain/flask-mail
Flask-Migrate 2.7.0 MIT http://github.com/miguelgrinberg/flask-migrate/
Flask-SQLAlchemy 2.5.1 BSD-3-Clause https://github.com/pallets/flask-sqlalchemy
Flask-WTF 0.14.3 BSD https://github.com/lepture/flask-wtf
Flask-Compress 1.9.0 MIT https://github.com/colour-science/flask-compress
Flask-WTF 0.15.1 BSD https://github.com/wtforms/flask-wtf
Flask-Compress 1.10.1 MIT https://github.com/colour-science/flask-compress
passlib 1.7.4 BSD https://passlib.readthedocs.io
pytz 2021.1 MIT http://pythonhosted.org/pytz
simplejson 3.17.2 MIT License https://github.com/simplejson/simplejson
pytz 2021.3 MIT http://pythonhosted.org/pytz
simplejson 3.17.5 MIT License https://github.com/simplejson/simplejson
six 1.16.0 MIT https://github.com/benjaminp/six
speaklater3 1.4 UNKNOWN https://github.com/ThomasWaldmann/speaklater
sqlparse 0.4.1 BSD-3-Clause https://github.com/andialbrecht/sqlparse
sqlparse 0.4.2 BSD-3-Clause https://github.com/andialbrecht/sqlparse
WTForms 2.3.3 BSD-3-Clause https://wtforms.readthedocs.io/
Flask-Paranoid 0.2.0 MIT http://github.com/miguelgrinberg/flask-paranoid/
psutil 5.8.0 BSD https://github.com/giampaolo/psutil
psycopg2 2.8.6 LGPL with exceptions https://psycopg.org/
python-dateutil 2.8.1 Dual License https://dateutil.readthedocs.io
python-dateutil 2.8.2 Dual License https://github.com/dateutil/dateutil
SQLAlchemy 1.3.24 MIT http://www.sqlalchemy.org
itsdangerous 1.1.0 BSD https://palletsprojects.com/p/itsdangerous/
Flask-Security-Too 4.0.1 MIT https://github.com/Flask-Middleware/flask-security
Flask-Security-Too 4.1.2 MIT https://github.com/Flask-Middleware/flask-security
bcrypt 3.2.0 Apache License, Version 2.0 https://github.com/pyca/bcrypt/
cryptography 3.4.7 BSD or Apache License, Version 2.0 https://github.com/pyca/cryptography
cryptography 3.4.8 BSD or Apache License, Version 2.0 https://github.com/pyca/cryptography
sshtunnel 0.4.0 MIT https://github.com/pahaz/sshtunnel
ldap3 2.9 LGPL v3 https://github.com/cannatag/ldap3
ldap3 2.9.1 LGPL v3 https://github.com/cannatag/ldap3
Flask-BabelEx 0.9.4 BSD http://github.com/mrjoes/flask-babelex
gssapi 1.6.12 LICENSE.txt https://github.com/pythongssapi/python-gssapi
Flask-SocketIO 5.0.3 MIT http://github.com/miguelgrinberg/Flask-SocketIO/
gssapi 1.6.14 LICENSE.txt https://github.com/pythongssapi/python-gssapi
Flask-SocketIO 5.1.1 UNKNOWN https://github.com/miguelgrinberg/flask-socketio
eventlet 0.31.0 UNKNOWN http://eventlet.net
httpagentparser 1.9.1 http://www.opensource.org/licenses/mit-license.php http://shon.github.com/httpagentparser
user-agents 2.2.0 MIT https://github.com/selwin/python-user-agents
pywinpty 1.1.1 Unknown Unknown
Authlib 0.15.4 BSD-3-Clause https://authlib.org/
Authlib 0.15.5 BSD-3-Clause https://authlib.org/
requests 2.25.1 Apache 2.0 https://requests.readthedocs.io
NOTE: This report was generated using Python 3.9. Full information may not be
@@ -69,66 +69,106 @@ Javascript Dependencies
Name Version Licence URL
---- ------- ------- ---
@babel/code-frame 7.14.5 MIT https://github.com/babel/babel.git
@babel/code-frame 7.12.13 MIT https://github.com/babel/babel.git
@babel/compat-data 7.14.0 MIT https://github.com/babel/babel.git
@babel/core 7.14.3 MIT https://github.com/babel/babel.git
@babel/generator 7.14.3 MIT https://github.com/babel/babel.git
@babel/helper-annotate-as-pure 7.12.13 MIT https://github.com/babel/babel.git
@babel/helper-compilation-targets 7.13.16 MIT https://github.com/babel/babel.git
@babel/helper-create-class-features-plugin 7.14.3 MIT https://github.com/babel/babel.git
@babel/helper-function-name 7.14.2 MIT https://github.com/babel/babel.git
@babel/helper-get-function-arity 7.12.13 MIT https://github.com/babel/babel.git
@babel/helper-member-expression-to-functions 7.13.12 MIT https://github.com/babel/babel.git
@babel/compat-data 7.14.7 MIT https://github.com/babel/babel.git
@babel/core 7.13.8 MIT https://github.com/babel/babel.git
@babel/generator 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-annotate-as-pure 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-compilation-targets 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-create-class-features-plugin 7.14.6 MIT https://github.com/babel/babel.git
@babel/helper-function-name 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-get-function-arity 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-hoist-variables 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-member-expression-to-functions 7.14.7 MIT https://github.com/babel/babel.git
@babel/helper-module-imports 7.13.12 MIT https://github.com/babel/babel.git
@babel/helper-module-transforms 7.14.2 MIT https://github.com/babel/babel.git
@babel/helper-optimise-call-expression 7.12.13 MIT https://github.com/babel/babel.git
@babel/helper-plugin-utils 7.13.0 MIT https://github.com/babel/babel.git
@babel/helper-replace-supers 7.14.3 MIT https://github.com/babel/babel.git
@babel/helper-module-transforms 7.13.0 MIT https://github.com/babel/babel.git
@babel/helper-optimise-call-expression 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-plugin-utils 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-replace-supers 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-simple-access 7.13.12 MIT https://github.com/babel/babel.git
@babel/helper-split-export-declaration 7.12.13 MIT https://github.com/babel/babel.git
@babel/helper-validator-identifier 7.14.0 MIT https://github.com/babel/babel.git
@babel/helper-validator-option 7.12.17 MIT https://github.com/babel/babel.git
@babel/helpers 7.14.0 MIT https://github.com/babel/babel.git
@babel/highlight 7.14.0 MIT https://github.com/babel/babel.git
@babel/parser 7.14.3 MIT https://github.com/babel/babel.git
@babel/helper-split-export-declaration 7.14.5 MIT https://github.com/babel/babel.git
@babel/helper-validator-identifier 7.14.9 MIT https://github.com/babel/babel.git
@babel/helper-validator-option 7.14.5 MIT https://github.com/babel/babel.git
@babel/helpers 7.13.0 MIT https://github.com/babel/babel.git
@babel/highlight 7.14.5 MIT https://github.com/babel/babel.git
@babel/parser 7.14.7 MIT https://github.com/babel/babel.git
@babel/plugin-proposal-class-properties 7.13.0 MIT https://github.com/babel/babel.git
@babel/plugin-syntax-jsx 7.12.13 MIT https://github.com/babel/babel.git
@babel/plugin-transform-react-display-name 7.14.2 MIT https://github.com/babel/babel.git
@babel/plugin-transform-react-jsx 7.14.3 MIT https://github.com/babel/babel.git
@babel/plugin-transform-react-jsx 7.13.12 MIT https://github.com/babel/babel.git
@babel/plugin-transform-react-jsx-development 7.12.17 MIT https://github.com/babel/babel.git
@babel/plugin-transform-react-pure-annotations 7.12.1 MIT https://github.com/babel/babel.git
@babel/preset-react 7.13.13 MIT https://github.com/babel/babel.git
@babel/template 7.12.13 MIT https://github.com/babel/babel.git
@babel/traverse 7.14.2 MIT https://github.com/babel/babel.git
@babel/types 7.14.2 MIT https://github.com/babel/babel.git
@babel/runtime 7.14.0 MIT https://github.com/babel/babel.git
@babel/template 7.14.5 MIT https://github.com/babel/babel.git
@babel/traverse 7.14.7 MIT https://github.com/babel/babel.git
@babel/types 7.15.4 MIT https://github.com/babel/babel.git
@date-io/core 1.3.13 MIT https://github.com/dmtrKovalenko/date-io
@date-io/date-fns 1.3.13 MIT https://github.com/dmtrKovalenko/date-io
@emotion/cache 11.4.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/cache
@emotion/hash 0.8.0 MIT https://github.com/emotion-js/emotion/tree/master/packages/hash
@emotion/is-prop-valid 0.8.8 MIT https://github.com/emotion-js/emotion/tree/master/packages/is-prop-valid
@emotion/memoize 0.7.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/memoize
@emotion/memoize 0.7.4 MIT https://github.com/emotion-js/emotion/tree/master/packages/memoize
@emotion/react 11.4.0 MIT https://github.com/emotion-js/emotion/tree/main/packages/react
@emotion/serialize 1.0.2 MIT https://github.com/emotion-js/emotion/tree/main/packages/serialize
@emotion/sheet 1.0.1 MIT https://github.com/emotion-js/emotion/tree/master/packages/sheet
@emotion/stylis 0.8.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/stylis
@emotion/unitless 0.7.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/unitless
@emotion/utils 1.0.0 MIT https://github.com/emotion-js/emotion/tree/master/packages/utils
@emotion/weak-memoize 0.2.5 MIT https://github.com/emotion-js/emotion/tree/master/packages/weak-memoize
@istanbuljs/schema 0.1.3 MIT git+https://github.com/istanbuljs/schema.git
@popperjs/core 2.9.2 MIT https://github.com/popperjs/popper-core.git
@projectstorm/geometry 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-canvas-core 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-core 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-defaults 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-routing 6.5.2 MIT https://github.com/projectstorm/react-diagrams.git
@material-ui/core 4.11.0 MIT https://github.com/mui-org/material-ui.git
@material-ui/icons 4.11.2 MIT https://github.com/mui-org/material-ui.git
@material-ui/lab 4.0.0-alpha.58 MIT https://github.com/mui-org/material-ui.git
@material-ui/pickers 3.2.10 MIT https://github.com/mui-org/material-ui-pickers
@material-ui/styles 4.11.4 MIT https://github.com/mui-org/material-ui.git
@material-ui/system 4.12.1 MIT https://github.com/mui-org/material-ui.git
@material-ui/types 5.1.0 MIT https://github.com/mui-org/material-ui.git
@material-ui/utils 4.11.2 MIT https://github.com/mui-org/material-ui.git
@popperjs/core 2.9.0 MIT https://github.com/popperjs/popper-core.git
@projectstorm/geometry 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-canvas-core 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-core 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-defaults 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@projectstorm/react-diagrams-routing 6.6.1 MIT https://github.com/projectstorm/react-diagrams.git
@simonwep/pickr 1.8.1 MIT https://github.com/Simonwep/pickr.git
@tippyjs/react 4.2.5 MIT git+https://github.com/atomiks/tippyjs-react.git
@sindresorhus/is 0.7.0 MIT https://github.com/sindresorhus/is.git
@tippyjs/react 4.2.3 MIT git+https://github.com/atomiks/tippyjs-react.git
@types/classnames 2.3.1 MIT Unknown
@types/component-emitter 1.2.10 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/json-schema 7.0.7 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/node 15.6.1 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/node 14.14.32 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/parse-json 4.0.0 MIT https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
@types/prop-types 15.7.3 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react 16.14.10 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react 16.14.18 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react-dom 16.9.14 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react-transition-group 4.4.1 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/scheduler 0.16.1 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/styled-jsx 2.2.8 MIT https://github.com/DefinitelyTyped/DefinitelyTyped.git
acitree 4.5.0-rc.7 MIT https://github.com/imsurinder90/jquery-aciTree.git
ajv 6.12.6 MIT https://github.com/ajv-validator/ajv.git
ajv 5.5.2 MIT https://github.com/epoberezkin/ajv.git
ajv-errors 1.0.1 MIT git+https://github.com/epoberezkin/ajv-errors.git
ajv-keywords 3.5.2 MIT git+https://github.com/epoberezkin/ajv-keywords.git
alertifyjs 1.7.1 MIT git@github.com:MohammadYounes/AlertifyJS.git
alphanum-sort 1.0.2 MIT https://github.com/TrySound/alphanum-sort.git
ansi-regex 2.1.1 MIT https://github.com/chalk/ansi-regex.git
ansi-styles 3.2.1 MIT https://github.com/chalk/ansi-styles.git
ansi-styles 4.3.0 MIT https://github.com/chalk/ansi-styles.git
ansi-styles 2.2.1 MIT https://github.com/chalk/ansi-styles.git
axios 0.21.1 MIT https://github.com/axios/axios.git
aspen-core 1.0.4 MIT git+https://github.com/neeksandhu/aspen-core.git
aspen-decorations 1.1.1 MIT git+https://github.com/neeksandhu/aspen-decorations.git
aspen-tree-model 1.0.5 MIT git+https://github.com/neeksandhu/aspen-tree-model.git
async 2.6.3 MIT https://github.com/caolan/async.git
axios 0.21.4 MIT https://github.com/axios/axios.git
babel-code-frame 6.26.0 MIT https://github.com/babel/babel/tree/master/packages/babel-code-frame
babel-generator 6.26.1 MIT https://github.com/babel/babel/tree/master/packages/babel-generator
babel-messages 6.23.0 MIT https://github.com/babel/babel/tree/master/packages/babel-messages
babel-plugin-styled-components 1.12.0 MIT https://github.com/styled-components/babel-plugin-styled-components.git
babel-plugin-syntax-jsx 6.18.0 MIT https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-jsx
babel-runtime 6.26.0 MIT https://github.com/babel/babel/tree/master/packages/babel-runtime
babel-template 6.26.0 MIT https://github.com/babel/babel/tree/master/packages/babel-template
babel-traverse 6.26.0 MIT https://github.com/babel/babel/tree/master/packages/babel-traverse
@@ -152,20 +192,23 @@ bignumber.js 7.2.1
bootstrap 4.6.0 MIT git+https://github.com/twbs/bootstrap.git
bootstrap4-toggle 3.6.1 MIT https://github.com/gitbrent/bootstrap4-toggle.git
brace-expansion 1.1.11 MIT git://github.com/juliangruber/brace-expansion.git
browserfs 1.4.3 MIT https://github.com/jvilk/BrowserFS.git
browserslist 4.16.6 MIT https://github.com/browserslist/browserslist.git
callsites 3.1.0 MIT https://github.com/sindresorhus/callsites.git
camelcase 6.2.0 MIT https://github.com/sindresorhus/camelcase.git
camelize 1.0.0 MIT git://github.com/substack/camelize.git
caniuse-api 3.0.0 MIT https://github.com/nyalab/caniuse-api.git
chalk 2.4.2 MIT https://github.com/chalk/chalk.git
chalk 4.1.1 MIT https://github.com/chalk/chalk.git
chalk 1.1.3 MIT https://github.com/chalk/chalk.git
chart.js 2.9.4 MIT https://github.com/chartjs/Chart.js.git
chartjs-color 2.4.1 MIT https://github.com/chartjs/chartjs-color.git
chartjs-color-string 0.6.0 MIT https://github.com/chartjs/chartjs-color-string.git
classnames 2.3.1 MIT https://github.com/JedWatson/classnames.git
closest 0.0.1 MIT https://github.com/ForbesLindesay/closest.git
clsx 1.1.1 MIT https://github.com/lukeed/clsx.git
co 4.6.0 MIT https://github.com/tj/co.git
codemirror 5.61.1 MIT https://github.com/codemirror/CodeMirror.git
codemirror 5.59.4 MIT https://github.com/codemirror/CodeMirror.git
color-convert 1.9.3 MIT https://github.com/Qix-/color-convert.git
color-convert 2.0.1 MIT https://github.com/Qix-/color-convert.git
color-name 1.1.3 MIT git@github.com:dfcreative/color-name.git
color-name 1.1.4 MIT git@github.com:colorjs/color-name.git
colord 2.0.0 MIT https://github.com/omgovich/colord.git
@@ -173,26 +216,35 @@ colorette 1.2.2
commander 7.2.0 MIT https://github.com/tj/commander.js.git
component-emitter 1.3.0 MIT https://github.com/component/emitter.git
concat-map 0.0.1 MIT git://github.com/substack/node-concat-map.git
convert-source-map 1.7.0 MIT git://github.com/thlorenz/convert-source-map.git
core-js 3.13.0 MIT https://github.com/zloirock/core-js.git
context-menu 2.0.0 MIT https://github.com/chipto/context-menu.git
convert-source-map 1.8.0 MIT git://github.com/thlorenz/convert-source-map.git
core-js 3.12.1 MIT https://github.com/zloirock/core-js.git
core-js 2.6.12 MIT https://github.com/zloirock/core-js.git
cosmiconfig 7.0.0 MIT git+https://github.com/davidtheclark/cosmiconfig.git
css-color-names 1.0.1 MIT git://github.com/bahamas10/css-color-names.git
css-color-names 0.0.4 MIT git://github.com/bahamas10/css-color-names.git
css-line-break 1.1.1 MIT git+ssh://git@github.com/niklasvh/css-line-break.git
css-loader 5.2.6 MIT https://github.com/webpack-contrib/css-loader.git
css-loader 5.1.1 MIT https://github.com/webpack-contrib/css-loader.git
css-to-react-native 3.0.0 MIT git+https://github.com/styled-components/css-to-react-native.git
css-tree 1.1.3 MIT https://github.com/csstree/csstree.git
css-vendor 2.0.8 MIT git@github.com:cssinjs/css-vendor.git
cssesc 3.0.0 MIT https://github.com/mathiasbynens/cssesc.git
cssnano 5.0.4 MIT https://github.com/cssnano/cssnano.git
cssnano-preset-default 5.1.1 MIT https://github.com/cssnano/cssnano.git
cssnano-utils 2.0.1 MIT https://github.com/cssnano/cssnano.git
csso 4.2.0 MIT https://github.com/css/csso.git
csstype 2.6.16 MIT https://github.com/frenic/csstype
csstype 3.0.8 MIT https://github.com/frenic/csstype
dagre 0.8.5 MIT https://github.com/dagrejs/dagre.git
date-fns 2.24.0 MIT https://github.com/date-fns/date-fns
debug 4.3.1 MIT git://github.com/visionmedia/debug.git
debug 2.6.9 MIT git://github.com/visionmedia/debug.git
deep-diff 1.0.2 MIT git://github.com/flitbit/diff.git
detect-indent 4.0.0 MIT https://github.com/sindresorhus/detect-indent.git
diff-arrays-of-objects 1.1.8 MIT git+https://github.com/malcolmvr/diff-arrays-of-objects.git
dom-helpers 5.2.0 MIT git+https://github.com/react-bootstrap/dom-helpers.git
dom-serializer 1.3.2 MIT git://github.com/cheeriojs/dom-renderer.git
dropzone 5.9.2 MIT https://github.com/dropzone/dropzone.git
dropzone 5.8.0 MIT https://github.com/dropzone/dropzone.git
emojis-list 3.0.0 MIT git+https://github.com/kikobeats/emojis-list.git
engine.io-client 5.1.1 MIT https://github.com/socketio/engine.io-client.git
engine.io-parser 4.0.2 MIT git@github.com:socketio/engine.io-parser.git
@@ -202,7 +254,8 @@ escape-string-regexp 1.0.5
fast-deep-equal 3.1.3 MIT git+https://github.com/epoberezkin/fast-deep-equal.git
fast-deep-equal 1.1.0 MIT git+https://github.com/epoberezkin/fast-deep-equal.git
fast-json-stable-stringify 2.1.0 MIT git://github.com/epoberezkin/fast-json-stable-stringify.git
follow-redirects 1.14.1 MIT git@github.com:follow-redirects/follow-redirects.git
filename-reserved-regex 2.0.0 MIT https://github.com/sindresorhus/filename-reserved-regex.git
follow-redirects 1.14.4 MIT git@github.com:follow-redirects/follow-redirects.git
gensync 1.0.0-beta.2 MIT https://github.com/loganfsmyth/gensync.git
globals 11.12.0 MIT https://github.com/sindresorhus/globals.git
globals 9.18.0 MIT https://github.com/sindresorhus/globals.git
@@ -219,6 +272,7 @@ html2canvas 1.0.0-rc.7
immutability-helper 3.1.1 MIT git+https://github.com/kolodny/immutability-helper.git
import-fresh 3.3.0 MIT https://github.com/sindresorhus/import-fresh.git
imports-loader 2.0.0 MIT https://github.com/webpack-contrib/imports-loader.git
insert-if 1.2.0 MIT git+https://github.com/chipto/insert-if.git
invariant 2.2.4 MIT https://github.com/zertosh/invariant
ip-address 7.1.0 MIT git://github.com/beaugunderson/ip-address.git
is-absolute-url 3.0.3 MIT https://github.com/sindresorhus/is-absolute-url.git
@@ -226,11 +280,14 @@ is-any-array 1.0.0
is-arrayish 0.2.1 MIT https://github.com/qix-/node-is-arrayish.git
is-color-stop 1.1.0 MIT git+https://github.com/pigcan/is-color-stop.git
is-finite 1.1.0 MIT https://github.com/sindresorhus/is-finite.git
is-in-browser 1.1.3 MIT git+https://github.com/tuxsudo/is-in-browser.git
is-relative 1.0.0 MIT https://github.com/jonschlinkert/is-relative.git
is-unc-path 1.0.0 MIT https://github.com/jonschlinkert/is-unc-path.git
istanbul-instrumenter-loader 3.0.1 MIT https://github.com/webpack-contrib/istanbul-instrumenter-loader.git
javascript-natural-sort 0.7.1 MIT https://github.com/Bill4Time/javascript-natural-sort.git
jquery 3.6.0 MIT https://github.com/jquery/jquery.git
jquery-contextmenu 2.9.2 MIT git://github.com/swisnl/jQuery-contextMenu.git
jquery-ui 1.12.1 MIT git://github.com/jquery/jquery-ui.git
jquery-ui 1.13.0 MIT git://github.com/jquery/jquery-ui.git
js-tokens 4.0.0 MIT https://github.com/lydell/js-tokens.git
js-tokens 3.0.2 MIT https://github.com/lydell/js-tokens.git
jsbn 1.1.0 MIT https://github.com/andyperlitch/jsbn.git
@@ -243,6 +300,14 @@ json-schema-traverse 0.3.1
json-source-map 0.6.1 MIT git+https://github.com/epoberezkin/json-source-map.git
json5 2.2.0 MIT git+https://github.com/json5/json5.git
json5 1.0.1 MIT git+https://github.com/json5/json5.git
jss 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-camel-case 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-default-unit 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-global 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-nested 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-props-sort 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-rule-value-function 10.5.1 MIT https://github.com/cssinjs/jss
jss-plugin-vendor-prefixer 10.5.1 MIT https://github.com/cssinjs/jss
karma-coverage 2.0.3 MIT git://github.com/karma-runner/karma-coverage.git
lines-and-columns 1.1.6 MIT https://github.com/eventualbuddha/lines-and-columns.git
loader-utils 2.0.0 MIT https://github.com/webpack/loader-utils.git
@@ -254,6 +319,8 @@ loose-envify 1.4.0
lunr 0.7.2 MIT https://github.com/olivernn/lunr.js.git
make-dir 3.1.0 MIT https://github.com/sindresorhus/make-dir.git
matches-selector 0.0.1 MIT https://github.com/ForbesLindesay/matches-selector.git
memoize-one 5.2.1 MIT https://github.com/alexreardon/memoize-one.git
mime 2.5.2 MIT https://github.com/broofa/mime
minimist 1.2.5 MIT git://github.com/substack/minimist.git
ml-array-max 1.2.3 MIT git+https://github.com/mljs/array.git
ml-array-min 1.2.2 MIT git+https://github.com/mljs/array.git
@@ -265,21 +332,28 @@ moment 2.24.0
moment-timezone 0.5.33 MIT https://github.com/moment/moment-timezone.git
ms 2.1.2 MIT https://github.com/zeit/ms.git
ms 2.0.0 MIT https://github.com/zeit/ms.git
nanocolors 0.1.12 MIT https://github.com/ai/nanocolors.git
nanoid 3.1.23 MIT https://github.com/ai/nanoid.git
nanopop 2.1.0 MIT https://github.com/Simonwep/nanopop.git
node-releases 1.1.72 MIT git+https://github.com/chicoxyzzy/node-releases.git
normalize-url 4.5.1 MIT https://github.com/sindresorhus/normalize-url.git
notificar 1.0.1 MIT git+https://github.com/neeksandhu/notificar.git
object-assign 4.1.1 MIT https://github.com/sindresorhus/object-assign.git
p-reduce 1.0.0 MIT https://github.com/sindresorhus/p-reduce.git
p-series 1.1.0 MIT https://github.com/sindresorhus/p-series.git
parent-module 1.0.1 MIT https://github.com/sindresorhus/parent-module.git
parse-json 5.2.0 MIT https://github.com/sindresorhus/parse-json.git
parseqs 0.0.6 MIT https://github.com/get/querystring.git
parseuri 0.0.6 MIT https://github.com/get/parseuri.git
path-fx 2.1.1 MIT git+https://github.com/NeekSandhu/path-fx.git
path-type 4.0.0 MIT https://github.com/sindresorhus/path-type.git
pathfinding 0.4.18 MIT git://github.com/qiao/PathFinding.js.git
performance-now 2.1.0 MIT git://github.com/braveg1rl/performance-now.git
pgadmin4-tree 1.0.0 MIT Unknown
picomodal 3.0.0 MIT https://github.com/Nycto/PicoModal.git
popper.js 1.16.1-lts MIT git+https://github.com/FezVrasta/popper.js.git
popper.js 1.16.1 MIT git+https://github.com/FezVrasta/popper.js.git
postcss 8.3.0 MIT https://github.com/postcss/postcss.git
postcss 8.2.15 MIT https://github.com/postcss/postcss.git
postcss-calc 8.0.0 MIT https://github.com/postcss/postcss-calc.git
postcss-colormin 5.1.1 MIT https://github.com/cssnano/cssnano.git
postcss-convert-values 5.0.1 MIT https://github.com/cssnano/cssnano.git
@@ -310,20 +384,36 @@ postcss-selector-parser 6.0.6
postcss-svgo 5.0.1 MIT https://github.com/cssnano/cssnano.git
postcss-unique-selectors 5.0.1 MIT https://github.com/cssnano/cssnano.git
postcss-value-parser 4.1.0 MIT https://github.com/TrySound/postcss-value-parser.git
prop-types 15.7.2 MIT https://github.com/facebook/prop-types.git
punycode 2.1.1 MIT https://github.com/bestiejs/punycode.js.git
raf 3.4.1 MIT git://github.com/chrisdickinson/raf.git
react 16.14.0 MIT git+https://github.com/facebook/react.git
react 17.0.2 MIT https://github.com/facebook/react.git
react-aspen 1.1.1 MIT https://github.com/neeksandhu/react-aspen.git
react-dom 16.14.0 MIT git+https://github.com/facebook/react.git
react-dom 17.0.2 MIT https://github.com/facebook/react.git
react-input-autosize 3.0.0 MIT https://github.com/JedWatson/react-input-autosize.git
react-is 16.13.1 MIT https://github.com/facebook/react.git
react-is 17.0.2 MIT https://github.com/facebook/react.git
react-select 4.3.1 MIT https://github.com/JedWatson/react-select/tree/master/packages/react-select
react-table 7.7.0 MIT https://github.com/tannerlinsley/react-table
react-virtualized-auto-sizer 1.0.6 MIT https://github.com/bvaughn/react-virtualized-auto-sizer.git
react-window 1.8.6 MIT https://github.com/bvaughn/react-window.git
regenerator-runtime 0.13.7 MIT https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime
regenerator-runtime 0.11.1 MIT https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime
repeating 2.0.1 MIT https://github.com/sindresorhus/repeating.git
resolve-from 4.0.0 MIT https://github.com/sindresorhus/resolve-from.git
rgb-regex 1.0.1 MIT https://github.com/regexps/rgb-regex.git
rgba-regex 1.0.0 MIT https://github.com/johnotander/rgba-regex.git
rifm 0.7.0 MIT https://github.com/istarkov/rifm.git
safe-buffer 5.1.2 MIT git://github.com/feross/safe-buffer.git
scheduler 0.19.1 MIT https://github.com/facebook/react.git
scheduler 0.20.2 MIT https://github.com/facebook/react.git
schema-utils 3.0.0 MIT https://github.com/webpack/schema-utils.git
schema-utils 0.3.0 MIT git+https://github.com/webpack-contrib/schema-utils.git
schema-utils 1.0.0 MIT https://github.com/webpack-contrib/schema-utils
select2 4.0.13 MIT git://github.com/select2/select2.git
shallowequal 1.1.0 MIT https://github.com/dashed/shallowequal.git
shim-loader 1.0.1 MIT https://github.com/zinserjan/shim-loader
slickgrid 2.3.16 MIT git+https://github.com/6pac/SlickGrid.git
snapsvg-cjs 0.0.6 MIT git+https://github.com/geelen/Snap.svg-cjs.git
@@ -334,21 +424,29 @@ split.js 1.6.4
stable 0.1.8 MIT https://github.com/Two-Screen/stable.git
strip-ansi 3.0.1 MIT https://github.com/chalk/strip-ansi.git
strip-comments 2.0.1 MIT https://github.com/jonschlinkert/strip-comments.git
styled-components 5.2.1 MIT git+https://github.com/styled-components/styled-components.git
stylehacks 5.0.1 MIT https://github.com/cssnano/cssnano.git
stylis 4.0.10 MIT https://github.com/thysultan/stylis.js
supports-color 5.5.0 MIT https://github.com/chalk/supports-color.git
supports-color 7.2.0 MIT https://github.com/chalk/supports-color.git
supports-color 2.0.0 MIT https://github.com/chalk/supports-color.git
svgo 2.3.0 MIT git://github.com/svg/svgo.git
supports-color 7.2.0 MIT https://github.com/chalk/supports-color.git
svgo 2.7.0 MIT git://github.com/svg/svgo.git
symbol-observable 1.2.0 MIT https://github.com/blesh/symbol-observable.git
tempusdominus-bootstrap-4 5.39.0 MIT https://github.com/tempusdominus/bootstrap-4.git
tempusdominus-core 5.19.0 MIT https://github.com/tempusdominus/core.git
timsort 0.3.0 MIT https://github.com/mziccard/node-timsort.git
tiny-emitter 2.1.0 MIT https://github.com/scottcorgan/tiny-emitter.git
tiny-warning 1.0.3 MIT https://github.com/alexreardon/tiny-warning.git
tippy.js 6.3.1 MIT git+https://github.com/atomiks/tippyjs.git
to-fast-properties 2.0.0 MIT https://github.com/sindresorhus/to-fast-properties.git
to-fast-properties 1.0.3 MIT https://github.com/sindresorhus/to-fast-properties.git
trim-right 1.0.1 MIT https://github.com/sindresorhus/trim-right.git
unc-path-regex 0.1.2 MIT https://github.com/regexhq/unc-path-regex.git
underscore 1.13.1 MIT git://github.com/jashkenas/underscore.git
uniqs 2.0.0 MIT git://github.com/fgnass/uniqs.git
url-loader 1.1.2 MIT https://github.com/webpack-contrib/url-loader.git
util-deprecate 1.0.2 MIT git://github.com/TooTallNate/util-deprecate.git
valid-filename 2.0.1 MIT https://github.com/sindresorhus/valid-filename.git
vendors 1.0.4 MIT https://github.com/wooorm/vendors.git
webpack-sources 0.2.3 MIT git+https://github.com/webpack/webpack-sources.git
wkx 0.5.0 MIT http://github.com/cschwarz/wkx.git
@@ -358,10 +456,11 @@ xterm-addon-fit 0.5.0
xterm-addon-search 0.8.0 MIT https://github.com/xtermjs/xterm.js
xterm-addon-web-links 0.4.0 MIT https://github.com/xtermjs/xterm.js
yeast 0.1.2 MIT https://github.com/unshiftio/yeast.git
@fortawesome/fontawesome-free 5.15.3 (CC-BY-4.0 AND OFL-1.1 AND MIT) https://github.com/FortAwesome/Font-Awesome
@fortawesome/fontawesome-free 5.15.4 (CC-BY-4.0 AND OFL-1.1 AND MIT) https://github.com/FortAwesome/Font-Awesome
@sphinxxxx/color-conversion 2.2.2 ISC git+https://github.com/Sphinxxxx/color-conversion.git
@trysound/sax 0.1.1 ISC git://github.com/svg/sax.git
@trysound/sax 0.2.0 ISC git://github.com/svg/sax.git
boolbase 1.0.0 ISC https://github.com/fb55/boolbase
css-color-keywords 1.0.0 ISC https://github.com/sonicdoe/css-color-keywords.git
css-declaration-sorter 6.0.3 ISC https://github.com/Siilwyn/css-declaration-sorter.git
electron-to-chromium 1.3.740 ISC https://github.com/kilian/electron-to-chromium/
icss-utils 5.1.0 ISC git+https://github.com/css-modules/icss-utils.git
@@ -372,13 +471,15 @@ minimatch 3.0.4
postcss-modules-extract-imports 3.0.0 ISC https://github.com/css-modules/postcss-modules-extract-imports.git
postcss-modules-scope 3.0.0 ISC https://github.com/css-modules/postcss-modules-scope.git
postcss-modules-values 4.0.0 ISC git+https://github.com/css-modules/postcss-modules-values.git
semver 7.3.5 ISC https://github.com/npm/node-semver
semver 7.3.4 ISC https://github.com/npm/node-semver
semver 5.7.1 ISC https://github.com/npm/node-semver
semver 6.3.0 ISC https://github.com/npm/node-semver
vanilla-picker 2.11.2 ISC https://github.com/Sphinxxxx/vanilla-picker.git
yallist 4.0.0 ISC git+https://github.com/isaacs/yallist.git
yaml 1.10.2 ISC https://github.com/eemeli/yaml.git
ace-builds 1.4.12 BSD-3-Clause https://github.com/ajaxorg/ace-builds.git
hoist-non-react-statics 3.3.2 BSD-3-Clause git://github.com/mridgway/hoist-non-react-statics.git
hyphenate-style-name 1.0.4 BSD-3-Clause git+ssh://git@github.com/rexxars/hyphenate-style-name.git
istanbul-lib-coverage 1.2.1 BSD-3-Clause git@github.com:istanbuljs/istanbuljs.git
istanbul-lib-coverage 3.0.0 BSD-3-Clause git+ssh://git@github.com/istanbuljs/istanbuljs.git
istanbul-lib-instrument 1.10.2 BSD-3-Clause git@github.com:istanbuljs/istanbuljs.git
@@ -386,34 +487,36 @@ istanbul-lib-instrument 4.0.3
istanbul-lib-report 3.0.0 BSD-3-Clause git+ssh://git@github.com/istanbuljs/istanbuljs.git
istanbul-lib-source-maps 4.0.0 BSD-3-Clause git+ssh://git@github.com/istanbuljs/istanbuljs.git
istanbul-reports 3.0.2 BSD-3-Clause git+ssh://git@github.com/istanbuljs/istanbuljs.git
react-transition-group 4.4.1 BSD-3-Clause https://github.com/reactjs/react-transition-group.git
source-map 0.5.7 BSD-3-Clause http://github.com/mozilla/source-map.git
source-map 0.6.1 BSD-3-Clause http://github.com/mozilla/source-map.git
source-map-js 0.6.2 BSD-3-Clause http://github.com/7rulnik/source-map.git
sprintf-js 1.1.2 BSD-3-Clause https://github.com/alexei/sprintf.js.git
bootstrap-datepicker 1.9.0 Apache-2.0 https://github.com/uxsolutions/bootstrap-datepicker.git
eve 0.5.4 Apache-2.0 git@github.com:adobe-webplatform/eve.git
indefinite-observable 2.0.1 Apache-2.0 git@github.com:material-motion/indefinite-observable-js.git
jmespath 0.15.0 Apache-2.0 git://github.com/jmespath/jmespath.js
jsoneditor 9.5.3 Apache-2.0 https://github.com/josdejong/jsoneditor.git
jsoneditor 9.5.6 Apache-2.0 https://github.com/josdejong/jsoneditor.git
paths-js 0.4.11 Apache-2.0 https://github.com/andreaferretti/paths-js.git
snapsvg 0.5.1 Apache-2.0 git@github.com:adobe-webplatform/Snap.svg.git
caniuse-lite 1.0.30001230 CC-BY-4.0 https://github.com/browserslist/caniuse-lite.git
css-select 3.1.2 BSD-2-Clause git://github.com/fb55/css-select.git
css-what 4.0.0 BSD-2-Clause https://github.com/fb55/css-what
css-select 4.1.3 BSD-2-Clause git://github.com/fb55/css-select.git
css-what 5.1.0 BSD-2-Clause https://github.com/fb55/css-what
domelementtype 2.2.0 BSD-2-Clause git://github.com/fb55/domelementtype.git
domhandler 4.2.0 BSD-2-Clause git://github.com/fb55/domhandler.git
domutils 2.6.0 BSD-2-Clause git://github.com/fb55/domutils.git
entities 2.2.0 BSD-2-Clause git://github.com/fb55/entities.git
esutils 2.0.3 BSD-2-Clause http://github.com/estools/esutils.git
leaflet 1.7.1 BSD-2-Clause git://github.com/Leaflet/Leaflet.git
nth-check 2.0.0 BSD-2-Clause https://github.com/fb55/nth-check
nth-check 2.0.1 BSD-2-Clause https://github.com/fb55/nth-check
uri-js 4.4.1 BSD-2-Clause http://github.com/garycourt/uri-js
FileSaver 0.10.0 UNKNOWN Unknown
heap 0.2.5 UNKNOWN git://github.com/qiao/heap.js.git
mdn-data 2.0.14 CC0-1.0 https://github.com/mdn/data.git
mousetrap 1.6.5 Apache-2.0 WITH LLVM-exception git://github.com/ccampbell/mousetrap.git
pako 1.0.11 (MIT AND Zlib) https://github.com/nodeca/pako.git
precond 0.2.3 MIT* https://github.com/MathieuTurcotte/node-precond.git
webcabin-docker 2.2.5 MIT* Unknown
tablesorter 2.31.3 (MIT OR GPL-2.0) git://github.com/Mottie/tablesorter.git
345 dependencies listed.
448 dependencies listed.
+1
View File
@@ -11,6 +11,7 @@ notes for it.
.. toctree::
:maxdepth: 1
release_notes_6_2
release_notes_6_1
release_notes_6_0
release_notes_5_7
+41
View File
@@ -0,0 +1,41 @@
************
Version 6.2
************
Release date: 2021-11-18
This release contains a number of bug fixes and new features since the release of pgAdmin4 6.1.
New features
************
| `Issue #3834 <https://redmine.postgresql.org/issues/3834>`_ - Added support of Aggregate and Operator node in view-only mode.
| `Issue #6953 <https://redmine.postgresql.org/issues/6953>`_ - Ensure that users should be able to modify the REMOTE_USER environment variable as per their environment by introducing the new config parameter WEBSERVER_REMOTE_USER.
Housekeeping
************
Bug fixes
*********
| `Issue #5427 <https://redmine.postgresql.org/issues/5427>`_ - Fixed pgAdmin freezing issue by providing the error message for the operation that can't perform due to lock on the particular table.
| `Issue #6780 <https://redmine.postgresql.org/issues/6780>`_ - Ensure that columns should be merged if the newly added column is present in the parent table.
| `Issue #6809 <https://redmine.postgresql.org/issues/6809>`_ - Fixed an issue where pgAdmin is not opening properly.
| `Issue #6832 <https://redmine.postgresql.org/issues/6832>`_ - Ensure that internal authentication when combined with other authentication providers, the order of internal source should not matter while picking up the provider.
| `Issue #6845 <https://redmine.postgresql.org/issues/6845>`_ - Ensure that inherit table icon should be visible properly in the tree view.
| `Issue #6859 <https://redmine.postgresql.org/issues/6859>`_ - Fixed an issue where properties panel is not updated when any object is added from the browser tree.
| `Issue #6896 <https://redmine.postgresql.org/issues/6896>`_ - Ensure that the user should be able to navigate browser tree objects using arrow keys from keyboard.
| `Issue #6905 <https://redmine.postgresql.org/issues/6905>`_ - Fixed an issue where database nodes are not getting loaded behind a reverse proxy with SSL.
| `Issue #6925 <https://redmine.postgresql.org/issues/6925>`_ - Fixed SQL syntax error if select "Custom auto-vacuum" option and not set Autovacuum option to Yes or No.
| `Issue #6939 <https://redmine.postgresql.org/issues/6939>`_ - Fixed an issue where older server group name displayed in the confirmation pop-up when the user removes server group.
| `Issue #6944 <https://redmine.postgresql.org/issues/6944>`_ - Fixed an issue where JSON editor preview colours have inappropriate contrast in dark mode.
| `Issue #6945 <https://redmine.postgresql.org/issues/6945>`_ - Fixed JSON Editor scrolling issue in code mode.
| `Issue #6940 <https://redmine.postgresql.org/issues/6940>`_ - Fixed an issue where user details are not shown when the non-admin user tries to connect to the shared server.
| `Issue #6949 <https://redmine.postgresql.org/issues/6949>`_ - Ensure that dialog should be opened when clicking on Reassign/Drop owned menu.
| `Issue #6954 <https://redmine.postgresql.org/issues/6954>`_ - Ensure that changing themes should work on Windows when system high contrast mode is enabled.
| `Issue #6972 <https://redmine.postgresql.org/issues/6972>`_ - Ensure that the Binary path for PG14 should be visible in the preferences.
| `Issue #6974 <https://redmine.postgresql.org/issues/6974>`_ - Added operators and aggregates in search objects.
| `Issue #6976 <https://redmine.postgresql.org/issues/6976>`_ - Fixed an issue where textarea should be allowed to resize and have more than 255 chars.
| `Issue #6981 <https://redmine.postgresql.org/issues/6981>`_ - Fixed an issue where SQL for index shows the same column multiple times.
| `Issue #6988 <https://redmine.postgresql.org/issues/6988>`_ - Reset the layout if pgAdmin4 detects the layout is in an inconsistent state.
+3
View File
@@ -32,6 +32,9 @@ and modify the values for the following parameters:
"WEBSERVER_AUTO_CREATE_USER", "Set the value to *True* if you want to automatically
create a pgAdmin user corresponding to a successfully authenticated Webserver user.
Please note that password is not stored in the pgAdmin database."
"WEBSERVER_REMOTE_USER", "The default value is REMOTE_USER, set this variable to any header
or environemnt variable to get the webserver remote user details. Possible values: REMOTE_USER,
HTTP_X_FORWARDED_USER, X-Forwarded-User."
Master Password
+5
View File
@@ -11,6 +11,11 @@
font-size: 14px;
background-color: #ebeef3;
}
@media screen and (forced-colors: active) {
body {
forced-color-adjust: none !important;
}
}
</style>
</head>
<body>
+5
View File
@@ -27,6 +27,11 @@
margin-right: auto;
margin-bottom: 10px;
}
@media screen and (forced-colors: active) {
body {
forced-color-adjust: none !important;
}
}
</style>
<!-- Disable/block all password saving in nw.js -->
+5
View File
@@ -11,6 +11,11 @@
font-size: 14px;
background-color: #ebeef3;
}
@media screen and (forced-colors: active) {
body {
forced-color-adjust: none !important;
}
}
</style>
</head>
<body>
+5
View File
@@ -11,6 +11,11 @@
font-size: 14px;
background-color: #ebeef3;
}
@media screen and (forced-colors: active) {
body {
forced-color-adjust: none !important;
}
}
</style>
</head>
<body>
+9 -2
View File
@@ -43,7 +43,7 @@ APP_ICON = 'pg-icon'
# Application version number components
APP_RELEASE = 6
APP_REVISION = 1
APP_REVISION = 2
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
# for GA releases.
@@ -52,7 +52,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 = 60100
APP_VERSION_INT = 60200
# DO NOT CHANGE!
# The application version string, constructed from the components
@@ -736,6 +736,13 @@ OAUTH2_AUTO_CREATE_USER = True
WEBSERVER_AUTO_CREATE_USER = True
# REMOTE_USER variable will be used to check the environment variable
# is set or not first, if not available,
# request header will be checked for the same.
# Possible values: REMOTE_USER, HTTP_X_FORWARDED_USER, X-Forwarded-User
WEBSERVER_REMOTE_USER = 'REMOTE_USER'
##########################################################################
# PSQL tool settings
##########################################################################
+5 -5
View File
@@ -66,7 +66,7 @@
"svgo-loader": "^2.2.0",
"terser-webpack-plugin": "^5.1.1",
"typescript": "^3.2.2",
"webfonts-loader": "^7.1.1",
"webfonts-loader": "^7.3.0",
"webpack": "^5.21.2",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-cli": "^4.5.0",
@@ -122,7 +122,7 @@
"istanbul-instrumenter-loader": "^3.0.1",
"jquery": "^3.6.0",
"jquery-contextmenu": "^2.9.2",
"jquery-ui": "^1.12.1",
"jquery-ui": "^1.13.0",
"json-bignumber": "^1.0.1",
"jsoneditor": "^9.5.4",
"karma-coverage": "^2.0.3",
@@ -136,7 +136,7 @@
"path-fx": "^2.0.0",
"pathfinding": "^0.4.18",
"paths-js": "^0.4.9",
"pgadmin4-tree": "git+https://github.com/EnterpriseDB/pgadmin4-treeview/#ab0af8e27c7bf24a750c998461c5a7aec2d4624f",
"pgadmin4-tree": "git+https://github.com/EnterpriseDB/pgadmin4-treeview/#90e62d4371d3d25a957b3ffc7c6cb81a928da06f",
"postcss": "^8.2.15",
"raf": "^3.4.1",
"react": "^17.0.1",
@@ -181,8 +181,8 @@
"test": "yarn run test:karma-once && yarn run bundle && python regression/runtests.py",
"pep8": "pycodestyle --config=../.pycodestyle ../docs && pycodestyle --config=../.pycodestyle ../pkg && pycodestyle --config=../.pycodestyle ../tools && pycodestyle --config=../.pycodestyle ../web",
"auditjs-html": "yarn audit --json | yarn run yarn-audit-html --output ../auditjs.html",
"auditjs": "yarn audit",
"auditpy": "safety check --full-report",
"auditjs": "yarn audit --groups dependencies",
"auditpy": "safety check --full-report -i 40493",
"audit": "yarn run auditjs && yarn run auditpy"
}
}
+7 -1
View File
@@ -104,7 +104,13 @@ if config.SERVER_MODE:
# Authentication sources
if len(config.AUTHENTICATION_SOURCES) > 0:
app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
# Creating a temporary auth source list removing INTERNAL
# This change is done to avoid selecting INTERNAL authentication when user
# mistakenly keeps that the first option.
auth_source = [x for x in config.AUTHENTICATION_SOURCES
if x != INTERNAL]
app.PGADMIN_EXTERNAL_AUTH_SOURCE = auth_source[0] \
if len(auth_source) > 0 else INTERNAL
else:
app.PGADMIN_EXTERNAL_AUTH_SOURCE = INTERNAL
+5 -1
View File
@@ -77,7 +77,11 @@ class WebserverAuthentication(BaseAuthentication):
return True
def get_user(self):
return request.environ.get('REMOTE_USER')
username = request.environ.get(config.WEBSERVER_REMOTE_USER)
if not username:
# One more try to get the Remote User from the hearders
username = request.headers.get(config.WEBSERVER_REMOTE_USER)
return username
def authenticate(self, form):
username = self.get_user()
@@ -0,0 +1,374 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
""" Implements Aggregate Node """
from functools import wraps
from flask import render_template
from flask_babelex import gettext
import pgadmin.browser.server_groups.servers.databases as database
from config import PG_DEFAULT_DRIVER
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
import SchemaChildModule
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.compile_template_name import compile_template_path
from pgadmin.utils.driver import get_driver
class AggregateModule(SchemaChildModule):
"""
class AggregateModule(SchemaChildModule)
A module class for Aggregate node derived from SchemaChildModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the Aggregate and it's base module.
* get_nodes(gid, sid, did, scid, agid)
- Method is used to generate the browser collection node.
* node_inode()
- Method is overridden from its base class to make the node as leaf node.
* script_load()
- Load the module script for schema, when any of the server node is
initialized.
"""
_NODE_TYPE = 'aggregate'
_COLLECTION_LABEL = gettext("Aggregates")
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the AggregateModule and it's base module.
Args:
*args:
**kwargs:
"""
super(AggregateModule, self).__init__(*args, **kwargs)
self.min_ver = 90100
self.max_ver = None
def get_nodes(self, gid, sid, did, scid):
"""
Generate the collection node
"""
yield self.generate_browser_collection_node(scid)
@property
def script_load(self):
"""
Load the module script for database, when any of the database node is
initialized.
"""
return database.DatabaseModule.node_type
@property
def node_inode(self):
return False
blueprint = AggregateModule(__name__)
class AggregateView(PGChildNodeView):
"""
This class is responsible for generating routes for Aggregate node
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the AggregateView and it's base view.
* check_precondition()
- This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
* list()
- This function is used to list all the Aggregate nodes within that
collection.
* nodes()
- This function will used to create all the child node within that
collection, Here it will create all the Aggregate node.
* properties(gid, sid, did, scid, agid)
- This function will show the properties of the selected Aggregate node
* sql(gid, sid, did, scid):
- This function will generate sql to show it in sql pane for the
selected Aggregate node.
"""
node_type = blueprint.node_type
node_label = "Aggregate"
parent_ids = [
{'type': 'int', 'id': 'gid'},
{'type': 'int', 'id': 'sid'},
{'type': 'int', 'id': 'did'},
{'type': 'int', 'id': 'scid'}
]
ids = [
{'type': 'int', 'id': 'agid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create', 'delete': 'delete'}
],
'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}]
})
def check_precondition(f):
"""
This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
"""
@wraps(f)
def wrap(*args, **kwargs):
# Here args[0] will hold self & kwargs will hold gid,sid,did
self = args[0]
self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
kwargs['sid']
)
self.conn = self.manager.connection(did=kwargs['did'])
self.datlastsysoid = \
self.manager.db_info[kwargs['did']]['datlastsysoid'] \
if self.manager.db_info is not None and \
kwargs['did'] in self.manager.db_info else 0
self.datistemplate = False
if (
self.manager.db_info is not None and
kwargs['did'] in self.manager.db_info and
'datistemplate' in self.manager.db_info[kwargs['did']]
):
self.datistemplate = self.manager.db_info[
kwargs['did']]['datistemplate']
# Set the template path for the SQL scripts
self.template_path = compile_template_path(
'aggregates/sql/',
self.manager.server_type,
self.manager.version
)
return f(*args, **kwargs)
return wrap
@check_precondition
def list(self, gid, sid, did, scid):
"""
This function is used to list all the aggregate nodes within that
collection.
Args:
gid: Server group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available aggregate nodes
"""
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), scid=scid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return ajax_response(
response=res['rows'],
status=200
)
@check_precondition
def nodes(self, gid, sid, did, scid):
"""
This function will used to create all the child node within that
collection.
Here it will create all the aggregate node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available aggregate child nodes
"""
res = []
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), scid=scid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
res.append(
self.blueprint.generate_browser_node(
row['oid'],
scid,
row['name'],
icon="icon-aggregate"
))
return make_json_response(
data=res,
status=200
)
@check_precondition
def node(self, gid, sid, did, scid, agid):
"""
This function will fetch properties of the aggregate node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
agid: Aggregate ID
Returns:
JSON of given aggregate node
"""
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), agid=agid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
return make_json_response(
data=self.blueprint.generate_browser_node(
row['oid'],
scid,
row['name'],
icon="icon-aggregate"
),
status=200
)
return gone(self.not_found_error_msg())
@check_precondition
def properties(self, gid, sid, did, scid, agid):
"""
This function will show the properties of the selected aggregate node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
scid: Schema ID
agid: Aggregate ID
Returns:
JSON of selected aggregate node
"""
status, res = self._fetch_properties(scid, agid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, scid, agid):
"""
This function fetch the properties for the specified object.
:param scid: Schema ID
:param agid: Aggregate ID
"""
SQL = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]),
scid=scid, agid=agid,
datlastsysoid=self.datlastsysoid)
status, res = self.conn.execute_dict(SQL)
if not status:
return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return False, gone(self.not_found_error_msg())
res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['oid'] <= self.datlastsysoid or self.datistemplate)
return True, res['rows'][0]
@check_precondition
def sql(self, gid, sid, did, scid, agid, **kwargs):
"""
This function will generates reverse engineered sql for aggregate
object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
agid: Aggregate ID
json_resp: True then return json response
"""
SQL = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]),
scid=scid, agid=agid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(self.not_found_error_msg())
data = res['rows'][0]
SQL = render_template("/".join([self.template_path,
self._CREATE_SQL]),
data=data)
sql_header = "-- Aggregate: {0};\n\n-- ".format(data['name'])
sql_header += render_template("/".join([self.template_path,
self._DELETE_SQL]),
data=data)
SQL = sql_header + '\n' + SQL.strip('\n')
return ajax_response(response=SQL)
AggregateView.register_node_view(blueprint)
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#cadff1;stroke:#6f6f6f;stroke-linecap:round;stroke-miterlimit:10;}.cls-2{fill:#9cbe44;}.cls-3{fill:#888;}</style></defs><rect class="cls-1" x="4.5" y="3.23" width="7" height="9.54" rx="1"/><rect class="cls-2" x="6.02" y="4.84" width="4" height="2"/><rect class="cls-3" x="6.14" y="7.66" width="1.5" height="1.36"/><rect class="cls-3" x="8.52" y="7.66" width="1.5" height="1.36"/><rect class="cls-3" x="6.14" y="10.02" width="1.5" height="1.36"/><rect class="cls-3" x="8.52" y="10.02" width="1.5" height="1.36"/></svg>

After

Width:  |  Height:  |  Size: 635 B

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#cadff1;stroke:#6f6f6f;stroke-linecap:round;stroke-miterlimit:10;}.cls-2{fill:#9cbe44;}.cls-3{fill:#888;}</style></defs><rect class="cls-1" x="2.48" y="1.21" width="7" height="9.54" rx="1"/><rect class="cls-2" x="4" y="2.83" width="4" height="2"/><rect class="cls-3" x="4.12" y="5.64" width="1.5" height="1.36"/><rect class="cls-3" x="6.5" y="5.64" width="1.5" height="1.36"/><rect class="cls-3" x="4.12" y="8" width="1.5" height="1.36"/><rect class="cls-3" x="6.5" y="8" width="1.5" height="1.36"/><rect class="cls-1" x="4.5" y="3.23" width="7" height="9.54" rx="1"/><rect class="cls-2" x="6.02" y="4.84" width="4" height="2"/><rect class="cls-3" x="6.14" y="7.66" width="1.5" height="1.36"/><rect class="cls-3" x="8.52" y="7.66" width="1.5" height="1.36"/><rect class="cls-3" x="6.14" y="10.02" width="1.5" height="1.36"/><rect class="cls-3" x="8.52" y="10.02" width="1.5" height="1.36"/><rect class="cls-1" x="6.52" y="5.25" width="7" height="9.54" rx="1"/><rect class="cls-2" x="8.04" y="6.86" width="4" height="2"/><rect class="cls-3" x="8.16" y="9.67" width="1.5" height="1.36"/><rect class="cls-3" x="10.54" y="9.67" width="1.5" height="1.36"/><rect class="cls-3" x="8.16" y="12.03" width="1.5" height="1.36"/><rect class="cls-3" x="10.54" y="12.03" width="1.5" height="1.36"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,86 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import AggregateSchema from './aggregate.ui';
define('pgadmin.node.aggregate', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/pgadmin', 'pgadmin.browser',
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, schemaChild) {
if (!pgBrowser.Nodes['coll-aggregate']) {
pgAdmin.Browser.Nodes['coll-aggregate'] =
pgAdmin.Browser.Collection.extend({
node: 'aggregate',
label: gettext('Aggregates'),
type: 'coll-aggregate',
columns: ['name', 'owner', 'description'],
canDrop: false,
canDropCascade: false,
});
}
if (!pgBrowser.Nodes['aggregate']) {
pgAdmin.Browser.Nodes['aggregate'] = schemaChild.SchemaChildNode.extend({
type: 'aggregate',
sqlAlterHelp: 'sql-alteraggregate.html',
sqlCreateHelp: 'sql-createaggregate.html',
label: gettext('Aggregate'),
collection_type: 'coll-aggregate',
hasSQL: true,
hasDepends: false,
canDrop: false,
canDropCascade: false,
Init: function() {
/* Avoid mulitple registration of menus */
if (this.initialized)
return;
this.initialized = true;
},
model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
// Default values!
initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0);
if (isNew) {
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
var schemaInfo = args.node_info.schema;
this.set({'owner': userInfo.name}, {silent: true});
this.set({'schema': schemaInfo._label}, {silent: true});
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: gettext('Aggregate'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
},{
id: 'owner', label: gettext('Owner'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
control: 'node-list-by-name',
node: 'role',
},{
id: 'description', label: gettext('Comment'), cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
}
],
}),
getSchema: ()=>{
let schema = new AggregateSchema();
return schema;
}
});
}
return pgBrowser.Nodes['aggregate'];
});
@@ -0,0 +1,185 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import gettext from 'sources/gettext';
export default class AggregateSchema extends BaseUISchema {
constructor(fieldOptions = {},initValues) {
super({
name: undefined,
oid: undefined,
owner: undefined,
description: undefined,
schema: null,
input_types: undefined,
state_type: undefined,
state_func: undefined,
state_data_size: 0,
final_type: undefined,
final_func: undefined,
final_func_modify: undefined,
final_extra_param: undefined,
initial_val: undefined,
moving_state_type: undefined,
moving_state_func: undefined,
moving_state_data_size: 0,
moving_final_type: undefined,
moving_final_func: undefined,
moving_final_func_modify: undefined,
moving_final_extra_param: undefined,
moving_initial_val: undefined,
moving_inverse_func: undefined,
combine_func: undefined,
serialization_func: undefined,
deserialization_func: undefined,
sort_oper: undefined,
...initValues
});
this.fieldOptions = fieldOptions;
}
get idAttribute() {
return 'oid';
}
get baseFields() {
return [
{
id: 'name', label: gettext('Name'),
type: 'text', readonly: true,
},
{
id: 'oid', label: gettext('OID'),
type: 'text', mode: ['properties'],
},
{
id: 'owner', label: gettext('Owner'),
type: 'text', readonly: true,
},
{
id: 'schema', label: gettext('Schema'),
mode: ['create', 'edit'],
type: 'text', readonly: true,
},
{
id: 'is_sys_obj', label: gettext('System aggregate?'),
cell: 'boolean', type: 'switch', mode: ['properties'],
},
{
id: 'description', label: gettext('Comment'),
type: 'multiline', mode: ['properties', 'create', 'edit'],
readonly: true,
},
{
id: 'input_types', label: gettext('Input types'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'state_type', label: gettext('State type'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'state_func', label: gettext('State function'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'state_data_size', label: gettext('State data size'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'final_type', label: gettext('Final type'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'final_func', label: gettext('Final function'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'final_func_modify', label: gettext('Final function modify'),
group: gettext('Options'), min_version: 110000,
type: 'text', readonly: true,
},
{
id: 'final_extra_param', label: gettext('Pass extra arguments to final function'),
group: gettext('Options'), type: 'switch', readonly: true,
},
{
id: 'initial_val', label: gettext('Initial condition'),
group: gettext('Options'),
type: 'text', readonly: true,
},
{
id: 'moving_state_type', label: gettext('State type'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'moving_state_func', label: gettext('State function'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'moving_state_data_size', label: gettext('State data size'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'moving_final_func', label: gettext('Final function'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'moving_final_func_modify', label: gettext('Final function modify'),
group: gettext('Moving Options'), min_version: 110000,
type: 'text', readonly: true,
},
{
id: 'moving_final_extra_param', label: gettext('Pass extra arguments to final function'),
group: gettext('Moving Options'), type: 'switch', readonly: true,
},
{
id: 'moving_inverse_func', label: gettext('Inverse function'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'moving_initial_val', label: gettext('Initial condition'),
group: gettext('Moving Options'),
type: 'text', readonly: true,
},
{
id: 'sort_oper', label: gettext('Sort operator'),
group: gettext('Advanced'),
type: 'text', readonly: true,
},
{
id: 'combine_func', label: gettext('Combine function'),
group: gettext('Advanced'),
type: 'text', readonly: true,
},
{
id: 'serialization_func', label: gettext('Serialization function'),
group: gettext('Advanced'),
type: 'text', readonly: true,
},
{
id: 'deserialization_func', label: gettext('Deserialization function'),
group: gettext('Advanced'),
type: 'text', readonly: true,
},
];
}
}
@@ -0,0 +1,24 @@
{% if data %}
CREATE AGGREGATE {{conn|qtIdent(data.schema, data.name)}}({% if data.input_types %}{{data.input_types}}{% endif %}) (
SFUNC = {{data.state_func}},
STYPE = {{data.state_type}} {% if data.state_data_size %},
SSPACE = {{data.state_data_size}}{% endif %}{% if data.final_func %},
FINALFUNC = {{data.final_func}}{% endif %}{% if data.final_extra_param %},
FINALFUNC_EXTRA{% endif %}{% if data.final_func_modify %},
FINALFUNC_MODIFY = {{data.final_func_modify}}{% endif %}{% if data.combine_func %},
COMBINEFUNC = {{data.combine_func}}{% endif %}{% if data.serialization_func %},
SERIALFUNC = {{data.serialization_func}}{% endif %}{% if data.deserialization_func %},
DESERIALFUNC = {{data.deserialization_func}}{% endif %}{% if data.initial_val %},
INITCOND = '{{data.initial_val}}'::text{% endif %}{% if data.moving_state_func %},
MSFUNC = {{data.moving_state_func}}{% endif %}{% if data.moving_inverse_func %},
MINVFUNC = {{data.moving_inverse_func}}{% endif %}{% if data.moving_state_type %},
MSTYPE = {{data.moving_state_type}}{% endif %}{% if data.moving_state_data_size %},
MSSPACE = {{data.moving_state_data_size}}{% endif %}{% if data.moving_final_func %},
MFINALFUNC = {{data.moving_final_func}}{% endif %}{% if data.moving_final_extra_param %},
MFINALFUNC_EXTRA{% endif %}{% if data.moving_final_func_modify %},
MFINALFUNC_MODIFY = {{data.moving_final_func_modify}}{% endif %}{% if data.moving_initial_val %},
MINITCOND = '{{data.moving_initial_val}}'::text{% endif %}{% if data.sort_oper %},
SORTOP = {{data.sort_oper}}{% endif %}
);
{% endif %}
@@ -0,0 +1,47 @@
SELECT aggfnoid::oid as oid, proname as name, ns.nspname as schema,
pg_catalog.pg_get_userbyid(proowner) as owner,
COALESCE(pg_catalog.pg_get_function_arguments(aggfnoid::oid), '') as input_types, proacl,
CASE WHEN ag.aggkind = 'n' THEN 'normal'
WHEN ag.aggkind = 'o' THEN 'ordered-set'
WHEN ag.aggkind = 'h' THEN 'hypothetical-set'
ELSE 'unknown' END as kind,
CASE WHEN aggtransfn = '-'::regproc THEN null ELSE aggtransfn END as state_func,
CASE WHEN aggfinalfn = '-'::regproc THEN null ELSE aggfinalfn END as final_func,
CASE WHEN aggcombinefn = '-'::regproc THEN null ELSE aggcombinefn END as combine_func,
CASE WHEN aggserialfn = '-'::regproc THEN null ELSE aggserialfn END as serialization_func,
CASE WHEN aggdeserialfn = '-'::regproc THEN null ELSE aggdeserialfn END as deserialization_func,
CASE WHEN aggmtransfn = '-'::regproc THEN null ELSE aggmtransfn END as moving_state_func,
CASE WHEN aggmfinalfn = '-'::regproc THEN null ELSE aggmfinalfn END as moving_final_func,
CASE WHEN aggminvtransfn = '-'::regproc THEN null ELSE aggminvtransfn END as moving_inverse_func,
CASE WHEN ag.aggfinalmodify = 'r' THEN 'READ_ONLY'
WHEN ag.aggfinalmodify = 's' THEN 'SHAREABLE'
WHEN ag.aggfinalmodify = 'w' THEN 'READ_WRITE'
ELSE 'unknown' END as final_func_modify,
CASE WHEN ag.aggmfinalmodify = 'r' THEN 'READ_ONLY'
WHEN ag.aggmfinalmodify = 's' THEN 'SHAREABLE'
WHEN ag.aggmfinalmodify = 'w' THEN 'READ_WRITE'
ELSE 'unknown' END as moving_final_func_modify,
agginitval as initial_val, aggminitval as moving_initial_val,
op.oprname as sort_oper, aggfinalextra as final_extra_param, aggmfinalextra as moving_final_extra_param,
aggtransspace as state_data_size, aggmtransspace as moving_state_data_size,
CASE WHEN (tt.typlen = -1 AND tt.typelem != 0) THEN
(SELECT at.typname FROM pg_type at WHERE at.oid = tt.typelem) || '[]'
ELSE tt.typname END as state_type,
CASE WHEN (tf.typlen = -1 AND tf.typelem != 0) THEN
(SELECT at.typname FROM pg_catalog.pg_type at WHERE at.oid = tf.typelem) || '[]'
ELSE tf.typname END as final_type,
CASE WHEN (tm.typlen = -1 AND tm.typelem != 0) THEN
(SELECT at.typname FROM pg_type at WHERE at.oid = tm.typelem) || '[]'
ELSE tm.typname END as moving_state_type,
description
FROM pg_catalog.pg_aggregate ag
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=pr.pronamespace
LEFT OUTER JOIN pg_catalog.pg_type tt on tt.oid=aggtranstype
LEFT OUTER JOIN pg_catalog.pg_type tf on tf.oid=prorettype
LEFT OUTER JOIN pg_catalog.pg_type tm on tm.oid=aggmtranstype
LEFT OUTER JOIN pg_catalog.pg_operator op on op.oid = ag.aggsortop
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=aggfnoid::oid AND des.classoid='pg_aggregate'::regclass)
WHERE pronamespace = {{scid}}::oid
{% if agid %} AND ag.aggfnoid = {{agid}}::oid {% endif %}
ORDER BY name;
@@ -0,0 +1,24 @@
{% if data %}
CREATE OR REPLACE AGGREGATE {{conn|qtIdent(data.schema, data.name)}}({% if data.input_types %}{{data.input_types}}{% endif %}) (
SFUNC = {{data.state_func}},
STYPE = {{data.state_type}} {% if data.state_data_size %},
SSPACE = {{data.state_data_size}}{% endif %}{% if data.final_func %},
FINALFUNC = {{data.final_func}}{% endif %}{% if data.final_extra_param %},
FINALFUNC_EXTRA{% endif %}{% if data.final_func_modify %},
FINALFUNC_MODIFY = {{data.final_func_modify}}{% endif %}{% if data.combine_func %},
COMBINEFUNC = {{data.combine_func}}{% endif %}{% if data.serialization_func %},
SERIALFUNC = {{data.serialization_func}}{% endif %}{% if data.deserialization_func %},
DESERIALFUNC = {{data.deserialization_func}}{% endif %}{% if data.initial_val %},
INITCOND = '{{data.initial_val}}'::text{% endif %}{% if data.moving_state_func %},
MSFUNC = {{data.moving_state_func}}{% endif %}{% if data.moving_inverse_func %},
MINVFUNC = {{data.moving_inverse_func}}{% endif %}{% if data.moving_state_type %},
MSTYPE = {{data.moving_state_type}}{% endif %}{% if data.moving_state_data_size %},
MSSPACE = {{data.moving_state_data_size}}{% endif %}{% if data.moving_final_func %},
MFINALFUNC = {{data.moving_final_func}}{% endif %}{% if data.moving_final_extra_param %},
MFINALFUNC_EXTRA{% endif %}{% if data.moving_final_func_modify %},
MFINALFUNC_MODIFY = {{data.moving_final_func_modify}}{% endif %}{% if data.moving_initial_val %},
MINITCOND = '{{data.moving_initial_val}}'::text{% endif %}{% if data.sort_oper %},
SORTOP = {{data.sort_oper}}{% endif %}
);
{% endif %}
@@ -0,0 +1,22 @@
{% if data %}
CREATE AGGREGATE {{conn|qtIdent(data.schema, data.name)}}({% if data.input_types %}{{data.input_types}}{% endif %}) (
SFUNC = {{data.state_func}},
STYPE = {{data.state_type}} {% if data.state_data_size %},
SSPACE = {{data.state_data_size}}{% endif %}{% if data.final_func %},
FINALFUNC = {{data.final_func}}{% endif %}{% if data.final_extra_param %},
FINALFUNC_EXTRA{% endif %}{% if data.combine_func %},
COMBINEFUNC = {{data.combine_func}}{% endif %}{% if data.serialization_func %},
SERIALFUNC = {{data.serialization_func}}{% endif %}{% if data.deserialization_func %},
DESERIALFUNC = {{data.deserialization_func}}{% endif %}{% if data.initial_val %},
INITCOND = '{{data.initial_val}}'::text{% endif %}{% if data.moving_state_func %},
MSFUNC = {{data.moving_state_func}}{% endif %}{% if data.moving_inverse_func %},
MINVFUNC = {{data.moving_inverse_func}}{% endif %}{% if data.moving_state_type %},
MSTYPE = {{data.moving_state_type}}{% endif %}{% if data.moving_state_data_size %},
MSSPACE = {{data.moving_state_data_size}}{% endif %}{% if data.moving_final_func %},
MFINALFUNC = {{data.moving_final_func}}{% endif %}{% if data.moving_final_extra_param %},
MFINALFUNC_EXTRA{% endif %}{% if data.moving_initial_val %},
MINITCOND = '{{data.moving_initial_val}}'::text{% endif %}{% if data.sort_oper %},
SORTOP = {{data.sort_oper}}{% endif %}
);
{% endif %}
@@ -0,0 +1,3 @@
{% if data %}
DROP AGGREGATE IF EXISTS {{conn|qtIdent(data.schema, data.name)}}({% if data.input_types %}{{data.input_types}}{% endif %}){% if cascade %} CASCADE{% endif %};
{% endif %}
@@ -0,0 +1,14 @@
SELECT aggfnoid::oid as oid,
proname || '(' || COALESCE(pg_catalog.pg_get_function_arguments(aggfnoid::oid), '') || ')' AS name,
pg_catalog.pg_get_userbyid(proowner) AS owner
FROM pg_aggregate ag
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
LEFT OUTER JOIN pg_catalog.pg_type tt on tt.oid=aggtranstype
LEFT OUTER JOIN pg_catalog.pg_type tf on tf.oid=prorettype
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=aggfnoid::oid AND des.classoid='pg_aggregate'::regclass)
{% if scid %}
WHERE pronamespace = {{scid}}::oid
{% elif agid %}
WHERE ag.aggfnoid = {{agid}}::oid
{% endif %}
ORDER BY name;
@@ -0,0 +1,39 @@
SELECT aggfnoid::oid as oid, proname as name, ns.nspname as schema,
pg_catalog.pg_get_userbyid(proowner) as owner,
COALESCE(pg_catalog.pg_get_function_arguments(aggfnoid::oid), '') as input_types, proacl,
CASE WHEN ag.aggkind = 'n' THEN 'normal'
WHEN ag.aggkind = 'o' THEN 'ordered-set'
WHEN ag.aggkind = 'h' THEN 'hypothetical-set'
ELSE 'unknown' END as kind,
CASE WHEN aggtransfn = '-'::regproc THEN null ELSE aggtransfn END as state_func,
CASE WHEN aggfinalfn = '-'::regproc THEN null ELSE aggfinalfn END as final_func,
CASE WHEN aggcombinefn = '-'::regproc THEN null ELSE aggcombinefn END as combine_func,
CASE WHEN aggserialfn = '-'::regproc THEN null ELSE aggserialfn END as serialization_func,
CASE WHEN aggdeserialfn = '-'::regproc THEN null ELSE aggdeserialfn END as deserialization_func,
CASE WHEN aggmtransfn = '-'::regproc THEN null ELSE aggmtransfn END as moving_state_func,
CASE WHEN aggmfinalfn = '-'::regproc THEN null ELSE aggmfinalfn END as moving_final_func,
CASE WHEN aggminvtransfn = '-'::regproc THEN null ELSE aggminvtransfn END as moving_inverse_func,
agginitval as initial_val, aggminitval as moving_initial_val,
op.oprname as sort_oper, aggfinalextra as final_extra_param, aggmfinalextra as moving_final_extra_param,
aggtransspace as state_data_size, aggmtransspace as moving_state_data_size,
CASE WHEN (tt.typlen = -1 AND tt.typelem != 0) THEN
(SELECT at.typname FROM pg_type at WHERE at.oid = tt.typelem) || '[]'
ELSE tt.typname END as state_type,
CASE WHEN (tf.typlen = -1 AND tf.typelem != 0) THEN
(SELECT at.typname FROM pg_catalog.pg_type at WHERE at.oid = tf.typelem) || '[]'
ELSE tf.typname END as final_type,
CASE WHEN (tm.typlen = -1 AND tm.typelem != 0) THEN
(SELECT at.typname FROM pg_type at WHERE at.oid = tm.typelem) || '[]'
ELSE tm.typname END as moving_state_type,
description
FROM pg_catalog.pg_aggregate ag
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=pr.pronamespace
LEFT OUTER JOIN pg_catalog.pg_type tt on tt.oid=aggtranstype
LEFT OUTER JOIN pg_catalog.pg_type tf on tf.oid=prorettype
LEFT OUTER JOIN pg_catalog.pg_type tm on tm.oid=aggmtranstype
LEFT OUTER JOIN pg_catalog.pg_operator op on op.oid = ag.aggsortop
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=aggfnoid::oid AND des.classoid='pg_aggregate'::regclass)
WHERE pronamespace = {{scid}}::oid
{% if agid %} AND ag.aggfnoid = {{agid}}::oid {% endif %}
ORDER BY name;
@@ -0,0 +1,18 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
SET application_name='pgadmin'
AS $BODY$
begin
select 1;
end;
$BODY$;
GRANT EXECUTE ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer) TO PUBLIC;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,15 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
AS $BODY$
begin
select 1;
end;
$BODY$;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,16 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
SET application_name='pgadmin'
AS $BODY$
begin
select 1;
end;
$BODY$;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,12 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
AS $BODY$
begin
select 1;
end;
$BODY$;
@@ -0,0 +1,311 @@
{
"scenarios": [
{
"type": "create",
"name": "Create function with all options.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function.sql",
"expected_msql_file": "create_function.msql"
},
{
"type": "alter",
"name": "Alter function comment",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"description": "Some comment"
},
"expected_sql_file": "alter_function_comment.sql",
"expected_msql_file": "alter_function_comment.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for alter.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function rename.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name":"Function3_$%{}[]()&*^!@\"'`\\/#"
},
"expected_sql_file": "alter_function_rename.sql",
"expected_msql_file": "alter_function_rename.msql"
},
{
"type": "alter",
"name": "Alter function code and add parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"prosrc": "begin\nselect '2';\nend\n",
"variables": {
"added": [
{
"name": "application_name",
"value": "appname"
}
]
}
},
"expected_sql_file": "alter_function_add_parameter.sql",
"expected_msql_file": "alter_function_add_parameter.msql"
},
{
"type": "alter",
"name": "Alter function delete parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"variables": {
"deleted": [
{
"name": "application_name",
"value": true
}
]
}
},
"expected_sql_file": "alter_function_delete_parameter.sql",
"expected_msql_file": "alter_function_delete_parameter.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for acl.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "postgres",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function add acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_add_acl.sql",
"expected_msql_file": "alter_function_add_acl.msql"
},
{
"type": "alter",
"name": "Alter function remove partial privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter function change grantee in privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"old_grantee": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_change_grantee_acl.sql",
"expected_msql_file": "alter_function_change_grantee_acl.msql"
},
{
"type": "alter",
"name": "Alter function delete acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_delete_acl.sql",
"expected_msql_file": "alter_function_delete_acl.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
}
]
}
@@ -0,0 +1,142 @@
{
"scenarios": [
{
"type": "create",
"name": "Create procedure",
"endpoint": "NODE-procedure.obj",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"name": "Proc1_$%{}[]()&*^!@\"'`\\/#",
"acl": [],
"arguments": [{"argtype": "integer", "argmode": "IN", "argname": "i1", "argdefval": ""}],
"funcowner": "postgres",
"lanname": "plpgsql",
"options": [],
"pronamespace": 2200,
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [],
"schema": "public",
"provolatile": null,
"proisstrict": false,
"proparallel": null,
"procost": null,
"proleakproof": false,
"probin": "$libdir/"
},
"expected_sql_file": "create_procedure.sql"
}, {
"type": "alter",
"name": "Alter procedure comment",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"description": "some comment"
},
"expected_sql_file": "alter_proc_comment.sql",
"expected_msql_file": "alter_proc_comment_msql.sql"
}, {
"type": "alter",
"name": "Alter procedure param",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"variables": {
"added": [{"name": "application_name", "value": "pgadmin"}]
}
},
"expected_sql_file": "alter_proc_param.sql",
"expected_msql_file": "alter_proc_param_msql.sql"
},
{
"type": "alter",
"name": "Alter procedure add privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
},
{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter procedure delete privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter procedure change privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "postgres",
"old_grantee": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_proc_change_grantee_priv.sql",
"expected_msql_file": "alter_proc_change_grantee_priv.msql"
},
{
"type": "delete",
"name": "Drop procedure",
"endpoint": "NODE-procedure.delete_id",
"data": {
}
}
]
}
@@ -0,0 +1,191 @@
{
"scenarios": [
{
"type": "create",
"name": "Create trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [],
"args": [],
"funcowner": "postgres",
"lanname": "plpgsql",
"options": [],
"pronamespace": 2200,
"prorettypename": "trigger",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [],
"schema": "public"
},
"expected_sql_file": "create_plain_trigger.sql"
}, {
"type": "alter",
"name": "Alter trigger function comment",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"description": "some comment"
},
"expected_sql_file": "alter_ptrig_comment.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 1 - Strict, Leakproof, Security of definer, Volatility",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"proisstrict": true,
"proleakproof": true,
"prosecdef": true,
"provolatile": "s"
},
"expected_sql_file": "alter_ptrig_set_1.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 2 - Cost, Volatility, Add Param",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"procost": "123",
"provolatile": "i",
"variables": {
"added": [{
"name": "application_name",
"value": "appname"
},{
"name": "search_path",
"value": "public, pg_temp"
}]
}
},
"expected_sql_file": "alter_ptrig_set_2.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 3 - Add Param, Change Param",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"variables": {
"added": [{
"name": "application_name",
"value": "appname2"
}],
"changed": [{
"name": "array_nulls",
"value": true
},{
"name": "search_path",
"value": "public, pg_catalog"
}]
}
},
"expected_sql_file": "alter_ptrig_set_3.sql"
}, {
"type": "delete",
"name": "Drop trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}, {
"type": "create",
"name": "Create full fledged trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": true
}
]
}],
"args": [],
"description": "some comment",
"funcowner": "postgres",
"lanname": "plpgsql",
"options": [],
"procost": "1234",
"proisstrict": true,
"proiswindow": true,
"proleakproof": true,
"pronamespace": 2200,
"proretset": true,
"prorettypename": "trigger",
"prorows": "4321",
"prosecdef": true,
"provolatile": "s",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [{
"name": "application_name",
"value": "appname"
},{
"name": "search_path",
"value": "public, pg_temp"
}],
"schema": "public"
},
"expected_sql_file": "create_plain_trigger_full.sql"
}, {
"type": "delete",
"name": "Drop full fledged trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}, {
"type": "create",
"name": "Create full fledged event trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [{
"grantee": "postgres",
"grantor": "postgres",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": true
}
]
}],
"args": [],
"description": "some comment",
"funcowner": "postgres",
"lanname": "plpgsql",
"options": [],
"procost": "1234",
"proisstrict": true,
"proiswindow": true,
"proleakproof": true,
"pronamespace": 2200,
"proretset": true,
"prorettypename": "event_trigger",
"prorows": "4321",
"prosecdef": true,
"provolatile": "s",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [{
"name": "application_name",
"value": "appname"
}],
"schema": "public"
},
"expected_sql_file": "create_event_trigger_full.sql"
}, {
"type": "delete",
"name": "Drop full fledged event trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}
]
}
@@ -0,0 +1,18 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
SET application_name='pgadmin'
AS $BODY$
begin
select 1;
end;
$BODY$;
GRANT EXECUTE ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer) TO PUBLIC;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,15 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
AS $BODY$
begin
select 1;
end;
$BODY$;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,16 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
SET application_name='pgadmin'
AS $BODY$
begin
select 1;
end;
$BODY$;
COMMENT ON PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(integer)
IS 'some comment';
@@ -0,0 +1,12 @@
-- PROCEDURE: public.Proc1_$%{}[]()&*^!@"'`\/#(integer)
-- DROP PROCEDURE IF EXISTS public."Proc1_$%{}[]()&*^!@""'`\/#"(integer);
CREATE OR REPLACE PROCEDURE public."Proc1_$%{}[]()&*^!@""'`\/#"(
IN i1 integer)
LANGUAGE 'plpgsql'
AS $BODY$
begin
select 1;
end;
$BODY$;
@@ -0,0 +1,323 @@
{
"scenarios": [
{
"type": "create",
"name": "Create function with all options.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function1_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proretset": false,
"proisstrict": true,
"prosecdef": true,
"proiswindow": true,
"proparallel": "u",
"procost": "100",
"prorows": "0",
"proleakproof": true,
"arguments": [
{
"argtype": "character varying",
"argmode": "IN",
"argname": "param",
"argdefval": "'1'"
}
],
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function.sql",
"expected_msql_file": "create_function.msql"
},
{
"type": "alter",
"name": "Alter function comment",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"description": "Some comment"
},
"expected_sql_file": "alter_function_comment.sql",
"expected_msql_file": "alter_function_comment.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for alter.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"prosecdef": true,
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function rename.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function3_$%{}[]()&*^!@\"'`\\/#"
},
"expected_sql_file": "alter_function_rename.sql",
"expected_msql_file": "alter_function_rename.msql"
},
{
"type": "alter",
"name": "Alter function code and add parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"prosrc": "begin\nselect '2';\nend\n",
"variables": {
"added": [
{
"name": "application_name",
"value": "appname"
}
]
}
},
"expected_sql_file": "alter_function_add_parameter.sql"
},
{
"type": "alter",
"name": "Alter function delete parameters.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"variables": {
"deleted": [
{
"name": "application_name",
"value": true
}
]
}
},
"expected_sql_file": "alter_function_delete_parameter.sql",
"expected_msql_file": "alter_function_delete_parameter.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
},
{
"type": "create",
"name": "Create function for acl.",
"endpoint": "NODE-function.obj",
"msql_endpoint": "NODE-function.msql",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"name": "Function2_$%{}[]()&*^!@\"'`\\/#",
"funcowner": "enterprisedb",
"pronamespace": 2200,
"prorettypename": "character varying",
"lanname": "plpgsql",
"provolatile": "v",
"proparallel": "u",
"prosecdef": true,
"arguments": [],
"procost": "100",
"prosrc": "begin\nselect '1';\nend",
"probin": "$libdir/",
"options": [],
"variables": [
{
"name": "enable_sort",
"value": true
}
],
"seclabels": [],
"acl": [],
"schema": "public"
},
"expected_sql_file": "create_function_for_alter.sql",
"expected_msql_file": "create_function_for_alter.msql"
},
{
"type": "alter",
"name": "Alter function add acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_add_acl.sql",
"expected_msql_file": "alter_function_add_acl.msql"
},
{
"type": "alter",
"name": "Alter function remove partial privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter function change grantee in privileges.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"old_grantee": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_change_grantee_acl.sql",
"expected_msql_file": "alter_function_change_grantee_acl.msql"
},
{
"type": "alter",
"name": "Alter function delete acl.",
"endpoint": "NODE-function.obj_id",
"msql_endpoint": "NODE-function.msql_id",
"sql_endpoint": "NODE-function.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
},
{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege_type": "X",
"privilege": true,
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_function_delete_acl.sql",
"expected_msql_file": "alter_function_delete_acl.msql"
},
{
"type": "delete",
"name": "Drop function",
"endpoint": "NODE-function.delete_id",
"data": {
}
}
]
}
@@ -0,0 +1,142 @@
{
"scenarios": [
{
"type": "create",
"name": "Create procedure",
"endpoint": "NODE-procedure.obj",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"name": "Proc1_$%{}[]()&*^!@\"'`\\/#",
"acl": [],
"arguments": [{"argtype": "integer", "argmode": "IN", "argname": "i1", "argdefval": ""}],
"funcowner": "enterprisedb",
"lanname": "plpgsql",
"options": [],
"pronamespace": 2200,
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [],
"schema": "public",
"provolatile": null,
"proisstrict": false,
"proparallel": null,
"procost": null,
"proleakproof": false,
"probin": "$libdir/"
},
"expected_sql_file": "create_procedure.sql"
}, {
"type": "alter",
"name": "Alter procedure comment",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"description": "some comment"
},
"expected_sql_file": "alter_proc_comment.sql",
"expected_msql_file": "alter_proc_comment_msql.sql"
}, {
"type": "alter",
"name": "Alter procedure param",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"variables": {
"added": [{"name": "application_name", "value": "pgadmin"}]
}
},
"expected_sql_file": "alter_proc_param.sql",
"expected_msql_file": "alter_proc_param_msql.sql"
},
{
"type": "alter",
"name": "Alter procedure add privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"added": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
},
{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter procedure delete privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"deleted": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
}
},
{
"type": "alter",
"name": "Alter procedure change privileges",
"endpoint": "NODE-procedure.obj_id",
"sql_endpoint": "NODE-procedure.sql_id",
"data": {
"acl": {
"changed": [
{
"grantee": "PUBLIC",
"grantor": "enterprisedb",
"old_grantee": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": false
}
]
}
]
}
},
"expected_sql_file": "alter_proc_change_grantee_priv.sql",
"expected_msql_file": "alter_proc_change_grantee_priv.msql"
},
{
"type": "delete",
"name": "Drop procedure",
"endpoint": "NODE-procedure.delete_id",
"data": {
}
}
]
}
@@ -0,0 +1,191 @@
{
"scenarios": [
{
"type": "create",
"name": "Create trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [],
"args": [],
"funcowner": "enterprisedb",
"lanname": "plpgsql",
"options": [],
"pronamespace": 2200,
"prorettypename": "trigger",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [],
"schema": "public"
},
"expected_sql_file": "create_plain_trigger.sql"
}, {
"type": "alter",
"name": "Alter trigger function comment",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"description": "some comment"
},
"expected_sql_file": "alter_ptrig_comment.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 1 - Strict, Leakproof, Security of definer, Volatility",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"proisstrict": true,
"proleakproof": true,
"prosecdef": true,
"provolatile": "s"
},
"expected_sql_file": "alter_ptrig_set_1.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 2 - Cost, Volatility, Add Param",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"procost": "123",
"provolatile": "i",
"variables": {
"added": [{
"name": "application_name",
"value": "appname"
},{
"name": "search_path",
"value": "public, pg_temp"
}]
}
},
"expected_sql_file": "alter_ptrig_set_2.sql"
}, {
"type": "alter",
"name": "Alter trigger function Set 3 - Add Param, Change Param",
"endpoint": "NODE-trigger_function.obj_id",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"variables": {
"added": [{
"name": "application_name",
"value": "appname2"
}],
"changed": [{
"name": "array_nulls",
"value": true
},{
"name": "search_path",
"value": "public, pg_catalog"
}]
}
},
"expected_sql_file": "alter_ptrig_set_3.sql"
}, {
"type": "delete",
"name": "Drop trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}, {
"type": "create",
"name": "Create full fledged trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": true
}
]
}],
"args": [],
"description": "some comment",
"funcowner": "enterprisedb",
"lanname": "plpgsql",
"options": [],
"procost": "1234",
"proisstrict": true,
"proiswindow": true,
"proleakproof": true,
"pronamespace": 2200,
"proretset": true,
"prorettypename": "trigger",
"prorows": "4321",
"prosecdef": true,
"provolatile": "v",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [{
"name": "application_name",
"value": "appname"
},{
"name": "search_path",
"value": "public, pg_temp"
}],
"schema": "public"
},
"expected_sql_file": "create_plain_trigger_full.sql"
}, {
"type": "delete",
"name": "Drop full fledged trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}, {
"type": "create",
"name": "Create full fledged event trigger function",
"endpoint": "NODE-trigger_function.obj",
"sql_endpoint": "NODE-trigger_function.sql_id",
"data": {
"name": "Trig1_$%{}[]()&*^!@\"'`\\/#",
"acl": [{
"grantee": "enterprisedb",
"grantor": "enterprisedb",
"privileges": [
{
"privilege": true,
"privilege_type": "X",
"with_grant": true
}
]
}],
"args": [],
"description": "some comment",
"funcowner": "enterprisedb",
"lanname": "plpgsql",
"options": [],
"procost": "1234",
"proisstrict": true,
"proiswindow": true,
"proleakproof": true,
"pronamespace": 2200,
"proretset": true,
"prorettypename": "event_trigger",
"prorows": "4321",
"prosecdef": true,
"provolatile": "v",
"prosrc": "begin\nselect 1;\nend;",
"seclabels": [],
"variables": [{
"name": "application_name",
"value": "appname"
}],
"schema": "public"
},
"expected_sql_file": "create_event_trigger_full.sql"
}, {
"type": "delete",
"name": "Drop full fledged event trigger function",
"endpoint": "NODE-trigger_function.delete_id",
"data": {
}
}
]
}
@@ -25,7 +25,7 @@ class ProcedureExecSQLTestCase(BaseTestGenerator):
('Fetch Procedure SQL to execute', dict(
url='/browser/procedure/exec_sql/', with_args=False, args="",
expected_sql="{0} {1}.{2}()")),
('Fetch Procedure with arguuments SQL to execute', dict(
('Fetch Procedure with arguments SQL to execute', dict(
url='/browser/procedure/exec_sql/', with_args=True,
args="arg1 bigint",
expected_sql="{0} {1}.{2}( <arg1 bigint> )"))
@@ -41,6 +41,9 @@ class ProcedureExecSQLTestCase(BaseTestGenerator):
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
if self.with_args and self.server_version >= 140000:
self.expected_sql = "{0} {1}.{2}( <IN arg1 bigint> )"
proc_name = "test_procedure_exec_sql_%s" % str(uuid.uuid4())[1:8]
proc_info = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, proc_name,
@@ -0,0 +1,377 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
""" Implements Operator Node """
from functools import wraps
from flask import render_template
from flask_babelex import gettext
import pgadmin.browser.server_groups.servers.databases as database
from config import PG_DEFAULT_DRIVER
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
import SchemaChildModule
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.compile_template_name import compile_template_path
from pgadmin.utils.driver import get_driver
class OperatorModule(SchemaChildModule):
"""
class OperatorModule(SchemaChildModule)
A module class for Operator node derived from SchemaChildModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the Operator and it's base module.
* get_nodes(gid, sid, did, scid, opid)
- Method is used to generate the browser collection node.
* node_inode()
- Method is overridden from its base class to make the node as leaf node.
* script_load()
- Load the module script for schema, when any of the server node is
initialized.
"""
_NODE_TYPE = 'operator'
_COLLECTION_LABEL = gettext("Operators")
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the OperatorModule and it's base module.
Args:
*args:
**kwargs:
"""
super(OperatorModule, self).__init__(*args, **kwargs)
self.min_ver = 90100
self.max_ver = None
def get_nodes(self, gid, sid, did, scid):
"""
Generate the collection node
"""
yield self.generate_browser_collection_node(scid)
@property
def script_load(self):
"""
Load the module script for database, when any of the database node is
initialized.
"""
return database.DatabaseModule.node_type
@property
def node_inode(self):
return False
blueprint = OperatorModule(__name__)
class OperatorView(PGChildNodeView):
"""
This class is responsible for generating routes for Operator node
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the OperatorView and it's base view.
* check_precondition()
- This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
* list()
- This function is used to list all the Operator nodes within that
collection.
* nodes()
- This function will used to create all the child node within that
collection, Here it will create all the Operator node.
* properties(gid, sid, did, scid, opid)
- This function will show the properties of the selected Operator node
* sql(gid, sid, did, scid):
- This function will generate sql to show it in sql pane for the
selected Operator node.
"""
node_type = blueprint.node_type
node_label = "Operator"
parent_ids = [
{'type': 'int', 'id': 'gid'},
{'type': 'int', 'id': 'sid'},
{'type': 'int', 'id': 'did'},
{'type': 'int', 'id': 'scid'}
]
ids = [
{'type': 'int', 'id': 'opid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create', 'delete': 'delete'}
],
'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}]
})
def check_precondition(f):
"""
This function will behave as a decorator which will checks
database connection before running view, it will also attaches
manager,conn & template_path properties to self
"""
@wraps(f)
def wrap(*args, **kwargs):
# Here args[0] will hold self & kwargs will hold gid,sid,did
self = args[0]
self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
kwargs['sid']
)
self.conn = self.manager.connection(did=kwargs['did'])
self.datlastsysoid = \
self.manager.db_info[kwargs['did']]['datlastsysoid'] \
if self.manager.db_info is not None and \
kwargs['did'] in self.manager.db_info else 0
self.datistemplate = False
if (
self.manager.db_info is not None and
kwargs['did'] in self.manager.db_info and
'datistemplate' in self.manager.db_info[kwargs['did']]
):
self.datistemplate = self.manager.db_info[
kwargs['did']]['datistemplate']
# Set the template path for the SQL scripts
self.template_path = compile_template_path(
'operators/sql/',
self.manager.server_type,
self.manager.version
)
return f(*args, **kwargs)
return wrap
@check_precondition
def list(self, gid, sid, did, scid):
"""
This function is used to list all the operator nodes within that
collection.
Args:
gid: Server group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available operator nodes
"""
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), scid=scid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return ajax_response(
response=res['rows'],
status=200
)
@check_precondition
def nodes(self, gid, sid, did, scid):
"""
This function will used to create all the child node within that
collection.
Here it will create all the operator node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available operator child nodes
"""
res = []
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), scid=scid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
res.append(
self.blueprint.generate_browser_node(
row['oid'],
scid,
row['name'],
icon="icon-operator"
))
return make_json_response(
data=res,
status=200
)
@check_precondition
def node(self, gid, sid, did, scid, opid):
"""
This function will fetch properties of the operator node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
opid: Operator ID
Returns:
JSON of given operator node
"""
SQL = render_template("/".join([self.template_path,
self._NODES_SQL]), opid=opid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
return make_json_response(
data=self.blueprint.generate_browser_node(
row['oid'],
scid,
row['name'],
icon="icon-operator"
),
status=200
)
return gone(self.not_found_error_msg())
@check_precondition
def properties(self, gid, sid, did, scid, opid):
"""
This function will show the properties of the selected operator node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
scid: Schema ID
opid: Operator ID
Returns:
JSON of selected operator node
"""
status, res = self._fetch_properties(scid, opid)
if not status:
return res
return ajax_response(
response=res,
status=200
)
def _fetch_properties(self, scid, opid):
"""
This function fetch the properties for the specified object.
:param scid: Schema ID
:param opid: Operator ID
"""
SQL = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]),
scid=scid, opid=opid,
datlastsysoid=self.datlastsysoid)
status, res = self.conn.execute_dict(SQL)
if not status:
return False, internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return False, gone(self.not_found_error_msg())
res['rows'][0]['is_sys_obj'] = (
res['rows'][0]['oid'] <= self.datlastsysoid or self.datistemplate)
return True, res['rows'][0]
@check_precondition
def sql(self, gid, sid, did, scid, opid):
"""
This function will generates reverse engineered sql for operator
object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
opid: Operator ID
json_resp: True then return json response
"""
SQL = render_template("/".join([self.template_path,
self._PROPERTIES_SQL]),
scid=scid, opid=opid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(self.not_found_error_msg())
data = res['rows'][0]
SQL = render_template("/".join([self.template_path,
self._CREATE_SQL]),
data=data)
sql_header = "-- Operator: {0};\n\n-- ".format(data['name'])
sql_header += render_template("/".join([self.template_path,
self._DELETE_SQL]),
name=data['name'],
oprnamespace=data['schema'],
lefttype=data['lefttype'],
righttype=data['righttype'],
)
SQL = sql_header + '\n' + SQL.strip('\n')
return ajax_response(response=SQL)
OperatorView.register_node_view(blueprint)
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#d4e3f3;}.cls-2{fill:#6f6f6f;}</style></defs><polygon class="cls-1" points="2.15 7.15 2.15 4.65 4.65 4.65 4.65 2.15 7.15 2.15 7.15 7.15 2.15 7.15"/><path class="cls-2" d="M6.65,2.65v4h-4V5.15h2.5V2.65h1.5m1-1H4.15v2.5H1.65v3.5h6v-6Z"/><polygon class="cls-1" points="4.15 9.15 4.15 6.65 6.65 6.65 6.65 4.15 9.15 4.15 9.15 9.15 4.15 9.15"/><path class="cls-2" d="M8.65,4.65v4h-4V7.15h2.5V4.65h1.5m1-1H6.15v2.5H3.65v3.5h6v-6Z"/><polygon class="cls-1" points="8.85 13.85 8.85 11.35 6.35 11.35 6.35 8.85 8.85 8.85 8.85 6.35 11.35 6.35 11.35 8.85 13.85 8.85 13.85 11.35 11.35 11.35 11.35 13.85 8.85 13.85"/><path class="cls-2" d="M10.85,6.85v2.5h2.5v1.5h-2.5v2.5H9.35v-2.5H6.85V9.35h2.5V6.85h1.5m1-1H8.35v2.5H5.85v3.5h2.5v2.5h3.5v-2.5h2.5V8.35h-2.5V5.85Z"/></svg>

After

Width:  |  Height:  |  Size: 875 B

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#d4e3f3;stroke:#6f6f6f;stroke-miterlimit:10;}</style></defs><polygon class="cls-1" points="13 6.85 9.15 6.85 9.15 3 6.85 3 6.85 6.85 3 6.85 3 9.15 6.85 9.15 6.85 13 9.15 13 9.15 9.15 13 9.15 13 6.85"/></svg>

After

Width:  |  Height:  |  Size: 325 B

@@ -0,0 +1,86 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import OperatorSchema from './operator.ui';
define('pgadmin.node.operator', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/pgadmin', 'pgadmin.browser',
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, schemaChild) {
if (!pgBrowser.Nodes['coll-operator']) {
pgAdmin.Browser.Nodes['coll-operator'] =
pgAdmin.Browser.Collection.extend({
node: 'operator',
label: gettext('Operators'),
type: 'coll-operator',
columns: ['name', 'owner', 'description'],
canDrop: false,
canDropCascade: false,
});
}
if (!pgBrowser.Nodes['operator']) {
pgAdmin.Browser.Nodes['operator'] = schemaChild.SchemaChildNode.extend({
type: 'operator',
sqlAlterHelp: 'sql-alteroperator.html',
sqlCreateHelp: 'sql-createoperator.html',
label: gettext('Operator'),
collection_type: 'coll-operator',
hasSQL: true,
hasDepends: false,
canDrop: false,
canDropCascade: false,
Init: function() {
/* Avoid mulitple registration of menus */
if (this.initialized)
return;
this.initialized = true;
},
model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
// Default values!
initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0);
if (isNew) {
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
var schemaInfo = args.node_info.schema;
this.set({'owner': userInfo.name}, {silent: true});
this.set({'schema': schemaInfo._label}, {silent: true});
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: gettext('Operator'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
},{
id: 'owner', label: gettext('Owner'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
control: 'node-list-by-name',
node: 'role',
},{
id: 'description', label: gettext('Comment'), cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
}
],
}),
getSchema: ()=>{
let schema = new OperatorSchema();
return schema;
}
});
}
return pgBrowser.Nodes['operator'];
});
@@ -0,0 +1,125 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import gettext from 'sources/gettext';
export default class OperatorSchema extends BaseUISchema {
constructor(fieldOptions = {},initValues) {
super({
name: undefined,
oid: undefined,
owner: undefined,
description: undefined,
schema: null,
lefttype: undefined,
righttype: undefined,
operproc:undefined,
joinproc: undefined,
restrproc: undefined,
commutator: undefined,
negator:undefined,
support_hash: false,
support_merge: false,
...initValues
});
this.fieldOptions = fieldOptions;
}
get idAttribute() {
return 'oid';
}
get baseFields() {
return [
{
id: 'name', label: gettext('Name'), type: 'tel',
readonly: true,
},
{
id: 'oid', label: gettext('OID'),
type: 'text', mode: ['properties']
},
{
id: 'owner', label: gettext('Owner'),
type: 'text', readonly: true,
},
{
id: 'schema', label: gettext('Schema'),
mode: ['create', 'edit'],
type: 'text', readonly: true,
},
{
id: 'is_sys_obj', label: gettext('System operator?'),
cell: 'boolean', type: 'switch', mode: ['properties'],
},
{
id: 'description', label: gettext('Comment'),
type: 'multiline', mode: ['properties', 'create', 'edit'],
readonly: true,
},
{
id: 'lefttype', label: gettext('Left type'),
group: gettext('Definition'),
type: 'text', readonly: true,
},
{
id: 'righttype', label: gettext('Right type'),
group: gettext('Definition'),
type: 'text', readonly: true,
},
{
id: 'resulttype', label: gettext('Result type'),
group: gettext('Definition'),
type: 'text', mode: ['properties'],
},
{
id: 'oprkind', label: gettext('Kind'),
group: gettext('Definition'),
type: 'text', mode: ['properties'],
},
{
id: 'operproc', label: gettext('Operator function'),
group: gettext('Definition'),
type: 'text', readonly: true,
},
{
id: 'restrproc', label: gettext('Restrict function'),
group: gettext('Implementation'),
type: 'text', readonly: true,
},
{
id: 'joinproc', label: gettext('Join function'),
group: gettext('Implementation'),
type: 'text', readonly: true,
},
{
id: 'commutator', label: gettext('Commutator'),
group: gettext('Implementation'),
type: 'text', readonly: true,
},
{
id: 'negator', label: gettext('Negator'),
group: gettext('Implementation'),
type: 'text', readonly: true,
},
{
id: 'support_hash', label: gettext('Supports hash'),
group: gettext('Implementation'),
cell: 'boolean', type: 'switch', readonly: true,
},
{
id: 'support_merge', label: gettext('Supports merge'),
group: gettext('Implementation'),
cell: 'boolean', type: 'switch', readonly: true,
}
];
}
}
@@ -0,0 +1,13 @@
{% if data %}
CREATE OPERATOR {{data.schema}}.{{data.name}} (
FUNCTION = {{data.operproc}}{% if data.lefttype %},
LEFTARG = {{data.lefttype}}{% endif %}{% if data.righttype %},
RIGHTARG = {{data.righttype}}{% endif %}{% if data.commutator %},
COMMUTATOR = {{data.commutator}}{% endif %}{% if data.negator %},
NEGATOR = {{data.negator}}{% endif %}{% if data.restrproc %},
RESTRICT = {{data.restrproc}}{% endif %}{% if data.joinproc %},
JOIN = {{data.joinproc}}{% endif %}{% if data.support_hash %},
HASHES{% endif %}{% if data.support_merge %}, MERGES{% endif %}
);
{% endif %}
@@ -0,0 +1,13 @@
{% if data %}
CREATE OPERATOR {{data.schema}}.{{data.name}} (
PROCEDURE = {{data.operproc}}{% if data.lefttype %},
LEFTARG = {{data.lefttype}}{% endif %}{% if data.righttype %},
RIGHTARG = {{data.righttype}}{% endif %}{% if data.commutator %},
COMMUTATOR = {{data.commutator}}{% endif %}{% if data.negator %},
NEGATOR = {{data.negator}}{% endif %}{% if data.restrproc %},
RESTRICT = {{data.restrproc}}{% endif %}{% if data.joinproc %},
JOIN = {{data.joinproc}}{% endif %}{% if data.support_hash %},
HASHES{% endif %}{% if data.support_merge %}, MERGES{% endif %}
);
{% endif %}
@@ -0,0 +1,13 @@
{% if lefttype %}
{% set ltype = lefttype %}
{% else %}
{% set ltype = none %}
{% endif %}
{% if righttype %}
{% set rtype = righttype %}
{% else %}
{% set rtype = none %}
{% endif %}
{% if name %}
DROP OPERATOR IF EXISTS {{conn|qtIdent(oprnamespace)}}.{{name}} ({{ltype}} , {{rtype}}){% if cascade %} CASCADE{% endif %};
{% endif %}
@@ -0,0 +1,23 @@
SELECT op.oid, pg_catalog.pg_get_userbyid(op.oprowner) as owner,
CASE WHEN lt.typname IS NOT NULL AND rt.typname IS NOT NULL THEN
op.oprname || ' (' || pg_catalog.format_type(lt.oid, NULL) || ', ' || pg_catalog.format_type(rt.oid, NULL) || ')'
WHEN lt.typname IS NULL AND rt.typname IS NOT NULL THEN
op.oprname || ' (' || pg_catalog.format_type(rt.oid, NULL) || ')'
WHEN lt.typname IS NOT NULL AND rt.typname IS NULL THEN
op.oprname || ' (' || pg_catalog.format_type(lt.oid, NULL) || ')'
ELSE op.oprname || '()'
END as name,
lt.typname as lefttype, rt.typname as righttype
FROM pg_catalog.pg_operator op
LEFT OUTER JOIN pg_catalog.pg_type lt ON lt.oid=op.oprleft
LEFT OUTER JOIN pg_catalog.pg_type rt ON rt.oid=op.oprright
JOIN pg_catalog.pg_type et on et.oid=op.oprresult
LEFT OUTER JOIN pg_catalog.pg_operator co ON co.oid=op.oprcom
LEFT OUTER JOIN pg_catalog.pg_operator ne ON ne.oid=op.oprnegate
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=op.oid AND des.classoid='pg_operator'::regclass)
{% if scid %}
WHERE op.oprnamespace = {{scid}}::oid
{% elif opid %}
WHERE op.oid = {{opid}}::oid
{% endif %}
ORDER BY op.oprname;
@@ -0,0 +1,25 @@
SELECT op.oid, op.oprname as name, ns.nspname as schema,
pg_catalog.pg_get_userbyid(op.oprowner) as owner,
op.oprcanhash as support_hash, op.oprcanmerge as support_merge,
ns.nspname as schema,
CASE WHEN op.oprkind = 'b' THEN 'infix'
WHEN op.oprkind = 'l' THEN 'prefix'
WHEN op.oprkind = 'r' THEN 'postfix'
ELSE 'unknown' END as oprkind, et.typname as resulttype,
pg_catalog.format_type(lt.oid, NULL) as lefttype,
pg_catalog.format_type(rt.oid, NULL) as righttype,
co.oprname as commutator, op.oprcode as operproc,
ne.oprname as negator, description,
CASE WHEN op.oprrest = '-'::regproc THEN null ELSE op.oprrest END as restrproc,
CASE WHEN op.oprjoin = '-'::regproc THEN null ELSE op.oprjoin END as joinproc
FROM pg_catalog.pg_operator op
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=op.oprnamespace
LEFT OUTER JOIN pg_catalog.pg_type lt ON lt.oid=op.oprleft
LEFT OUTER JOIN pg_catalog.pg_type rt ON rt.oid=op.oprright
JOIN pg_catalog.pg_type et on et.oid=op.oprresult
LEFT OUTER JOIN pg_catalog.pg_operator co ON co.oid=op.oprcom
LEFT OUTER JOIN pg_catalog.pg_operator ne ON ne.oid=op.oprnegate
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=op.oid AND des.classoid='pg_operator'::regclass)
WHERE op.oprnamespace = {{scid}}::oid
{% if opid %} AND op.oid = {{opid}}::oid {% endif %}
ORDER BY op.oprname;
@@ -29,6 +29,7 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
columns import utils as column_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
constraints.exclusion_constraint import utils as exclusion_utils
from pgadmin.utils.exception import ExecuteError
class TableModule(SchemaChildModule):
@@ -318,19 +319,19 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare):
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 \
table_info['is_inherits'] > '0') 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')\
table_info['is_inherited'] > '0')\
or ('relhassubclass' in table_info and
table_info['relhassubclass']):
default_val = 'icon-table-multi-inherit'
else:
default_val = 'icon-table-inherits'
elif ('is_inherited' in table_info and
table_info['is_inherited'] == '1')\
table_info['is_inherited'] > '0')\
or ('relhassubclass' in table_info and
table_info['relhassubclass']):
default_val = 'icon-table-inherited'
@@ -1024,6 +1025,11 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare):
if not status:
return res
lock_on_table = self.get_table_locks(did, res['rows'][0])
if lock_on_table != '':
return ExecuteError(
error_msg=str(lock_on_table.json['info']))
return super(TableView, self).update(
gid, sid, did, scid, tid, data=data, res=res)
except Exception as e:
@@ -1070,6 +1076,10 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare):
)
)
lock_on_table = self.get_table_locks(did, res['rows'][0])
if lock_on_table != '':
return lock_on_table
status, res = super(TableView, self).delete(gid, sid, did,
scid, tid, res)
@@ -99,6 +99,9 @@ def get_column_details(conn, idx, data, mode='properties', template_path=None):
"/".join([template_path, 'column_details.sql']), idx=idx
)
status, rset = conn.execute_2darray(SQL)
# Remove column if duplicate column is present in list.
rset['rows'] = [i for n, i in enumerate(rset['rows']) if
i not in rset['rows'][n + 1:]]
if not status:
return internal_server_error(errormsg=rset)
@@ -115,12 +115,12 @@ define('pgadmin.node.rule', [
{
name: 'enable_rule', node: 'rule', module: this,
applies: ['object', 'context'], callback: 'enable_rule',
category: 'connect', priority: 3, label: gettext('Enable rule'),
category: 'connect', priority: 3, label: gettext('Enable'),
icon: 'fa fa-check', enable: 'canCreate_with_rule_enable',
},{
name: 'disable_rule', node: 'rule', module: this,
applies: ['object', 'context'], callback: 'disable_rule',
category: 'drop', priority: 3, label: gettext('Disable rule'),
category: 'drop', priority: 3, label: gettext('Disable'),
icon: 'fa fa-times', enable: 'canCreate_with_rule_disable'
}
]);
@@ -205,6 +205,9 @@ define('pgadmin.node.table', [
t.select(i);
}, 10);
}
if (res.success == 2) {
Alertify.error(res.info, 0);
}
})
.fail(function(xhr, status, error) {
Alertify.pgRespErrorNotify(xhr, error);
@@ -537,7 +537,24 @@ export default class TableSchema extends BaseUISchema {
tabColsResponse.then((res)=>{
resolve((state)=>{
let finalCols = res.map((col)=>obj.columnsSchema.getNewData(col));
finalCols = [...state.columns, ...finalCols];
let currentSelectedCols = [];
if (!_.isEmpty(state.columns)){
currentSelectedCols = state.columns;
}
let colNameList = [];
state.columns.forEach((col=>{
colNameList.push(col.name);
}));
for (let col of Object.values(finalCols)) {
if(!colNameList.includes(col.name)){
currentSelectedCols.push(col);
}
}
if (!_.isEmpty(currentSelectedCols)){
finalCols = currentSelectedCols;
}
obj.changeColumnOptions(finalCols);
return {
adding_inherit_cols: false,
@@ -17,7 +17,7 @@
{% set empty_bracket = "\n(\n)"%}
{% endif %}
{% set with_clause = false%}
{% if data.fillfactor or data.parallel_workers or data.toast_tuple_target or data.autovacuum_custom or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum or data.toast_autovacuum_enabled in ('t', 'f') %}
{% if data.fillfactor or data.parallel_workers or data.toast_tuple_target or (data.autovacuum_custom and data.add_vacuum_settings_in_sql) or data.autovacuum_enabled in ('t', 'f') or (data.toast_autovacuum and data.add_vacuum_settings_in_sql) or data.toast_autovacuum_enabled in ('t', 'f') %}
{% set with_clause = true%}
{% endif %}
CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{conn|qtIdent(data.schema, data.name)}}{{empty_bracket}}
@@ -0,0 +1,8 @@
SELECT
usename,
application_name
FROM
pg_catalog.pg_stat_activity
WHERE
pid = {{ pid }}
ORDER BY pid
@@ -0,0 +1,23 @@
SELECT
pid,
locktype,
datname,
relation::regclass,
page,
tuple,
virtualxid
transactionid,
classid::regclass,
objid,
objsubid,
virtualtransaction,
mode,
granted,
fastpath
FROM
pg_catalog.pg_locks l
LEFT OUTER JOIN pg_catalog.pg_database d ON (l.database = d.oid)
{% if did %}WHERE
datname = (SELECT datname FROM pg_catalog.pg_database WHERE oid = {{ did }}){% endif %}
ORDER BY
pid, locktype
@@ -79,12 +79,12 @@ define('pgadmin.node.trigger', [
},{
name: 'enable_trigger', node: 'trigger', module: this,
applies: ['object', 'context'], callback: 'enable_trigger',
category: 'connect', priority: 3, label: gettext('Enable trigger'),
category: 'connect', priority: 3, label: gettext('Enable'),
icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable',
},{
name: 'disable_trigger', node: 'trigger', module: this,
applies: ['object', 'context'], callback: 'disable_trigger',
category: 'drop', priority: 3, label: gettext('Disable trigger'),
category: 'drop', priority: 3, label: gettext('Disable'),
icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable',
},{
name: 'create_trigger_onView', node: 'view', module: this,
@@ -49,6 +49,7 @@ from pgadmin.utils.preferences import Preferences
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
import VacuumSettings
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.dashboard import locks
class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
@@ -1952,6 +1953,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
data = res['rows'][0]
lock_on_table = self.get_table_locks(did, data)
if lock_on_table != '':
return lock_on_table
sql = render_template("/".join([self.table_template_path,
'truncate.sql']),
data=data, cascade=is_cascade,
@@ -2004,6 +2009,41 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
'scid': scid
}
def get_table_locks(self, did, data):
"""
This function returns the lock details if there is any on table
:param did:
:param data:
:return:
"""
sql = render_template(
"/".join([self.table_template_path, 'locks.sql']), did=did
)
status, lock_table_result = self.conn.execute_dict(sql)
for row in lock_table_result['rows']:
if row['relation'].strip('\"') == data['name']:
sql = render_template(
"/".join([self.table_template_path,
'get_application_name.sql']), pid=row['pid']
)
status, res = self.conn.execute_dict(sql)
application_name = res['rows'][0]['application_name']
return make_json_response(
success=2,
info=gettext(
"The table is currently locked and the "
"operation cannot be completed. "
"Please try again later. "
"\r\nBlocking Process ID : {0} "
"Application Name : {1}").format(row['pid'],
application_name)
)
return ''
def get_schema_and_table_name(self, tid):
"""
This function will fetch the schema qualified name of the
@@ -2056,8 +2096,18 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
if data is None:
if vacuum_key in old_data:
for opt in old_data[vacuum_key]:
if 'value' in opt and opt['value'] is None:
if 'add_vacuum_settings_in_sql' not in old_data:
old_data['add_vacuum_settings_in_sql'] = False
if ('value' in opt and opt['value'] is None) or \
('value' in opt and opt['value'] == ''):
opt.pop('value')
if 'value' in opt and 'add_vacuum_settings_in_sql' in \
old_data and not \
old_data['add_vacuum_settings_in_sql']:
old_data['add_vacuum_settings_in_sql'] = True
# Iterate vacuum table
elif vacuum_key in data and 'changed' in data[vacuum_key] \
and vacuum_key in old_data:
@@ -16,7 +16,8 @@ _default_database_response = [
{
'typname': 'type name',
'elemoid': 1560,
'is_collatable': True
'is_collatable': True,
'oid': 16635
}
]
_default_expected_function_output = [
@@ -28,7 +29,8 @@ _default_expected_function_output = [
'length': True,
'min_val': 1,
'max_val': 2147483647,
'is_collatable': True
'is_collatable': True,
'oid': 16635
}
]
_default_manager = dict(
@@ -182,7 +182,8 @@ class DataTypeReader:
'label': row['typname'], 'value': row['typname'],
'typval': typeval, 'precision': precision,
'length': length, 'min_val': min_val, 'max_val': max_val,
'is_collatable': row['is_collatable']
'is_collatable': row['is_collatable'],
'oid': row['oid']
})
except Exception as e:
@@ -129,7 +129,7 @@ define('pgadmin.node.role', [
var tree = pgBrowser.tree,
_i = tree.selected(),
_d = _i && _i.length == 1 ? tree.itemData(_i) : undefined,
_d = _i ? tree.itemData(_i) : undefined,
obj = this, finalUrl, old_role_name;
//RoleReassign Model (Objects like role, database)
@@ -435,7 +435,7 @@ define('pgadmin.node.role', [
// Find current/selected node
var tree = pgBrowser.tree,
_i = tree.selected(),
_d = _i && _i.length == 1 ? tree.itemData(_i) : undefined,
_d = _i ? tree.itemData(_i) : undefined,
node = _d && pgBrowser.Nodes[_d._type];
finalUrl = obj.generate_url(_i, 'reassign' , _d, true);
@@ -202,7 +202,9 @@
"expected_data": {
"status_code": 200,
"error_msg": null,
"test_result_data": {}
"test_result_data": {
"result": "REASSIGN OWNED BY role_user_1 TO CURRENT_ROLE"
}
}
},
{
@@ -813,14 +813,12 @@ define('pgadmin.node.server', [
var connect_to_server = function(obj, data, tree, item, reconnect) {
// Open properties dialog in edit mode
const selectedTreeNode = tree.selected().length > 0 ? tree.selected() : tree.first();
const selectedTreeNodeData = selectedTreeNode && selectedTreeNode.length === 1 ? tree.itemData(selectedTreeNode) : undefined;
var server_url = obj.generate_url(item, 'obj', data, true);
// Fetch the updated data
$.get(server_url)
.done(function(res) {
if (res.shared && _.isNull(res.username) && data.user_id != current_user.id){
if (selectedTreeNodeData._type == 'server' && !res.service){
if (!res.service){
pgAdmin.Browser.Node.callbacks.show_obj_properties.call(
pgAdmin.Browser.Nodes[tree.itemData(item)._type], {action: 'edit'}
);
@@ -143,7 +143,7 @@ export default class ServerSchema extends BaseUISchema {
mode: ['properties', 'create', 'edit'],
readonly: function(state){
var serverOwner = obj.userId;
if (obj.isNew(state) && serverOwner != current_user.id) {
if (!obj.isNew(state) && serverOwner != current_user.id) {
return true;
}
return false;
@@ -102,11 +102,18 @@ class ServerType(object):
bin_paths_server_based = \
copy.deepcopy(BINARY_PATHS['as_bin_paths'])
bin_path_dict = \
{item['version']: item for item in bin_paths_server_based}
old_path_dict = \
{item['version']: item for item in json.loads(old_path)}
for item in bin_path_dict:
bin_path_dict[item].update(old_path_dict.get(item, {}))
bin_paths_server_based = list(bin_path_dict.values())
if not ServerType.is_binary_path_of_type_json(old_path):
set_binary_path(old_path, bin_paths_server_based,
key, set_as_default=True)
else:
bin_paths_server_based = json.loads(old_path)
# Set the DEFAULT_BINARY_PATHS if any
ServerType.set_default_binary_path(bin_paths_server_based, key)
+17 -12
View File
@@ -430,7 +430,7 @@ define('pgadmin.browser', [
// Stored layout in database from the previous session
var layout = pgBrowser.utils.layout;
obj.restore_layout(obj.docker, layout, obj.buildDefaultLayout.bind(obj));
obj.restore_layout(obj.docker, layout, obj.buildDefaultLayout.bind(obj), true);
obj.docker.on(wcDocker.EVENT.LAYOUT_CHANGED, function() {
obj.save_current_layout('Browser/Layout', obj.docker);
@@ -440,14 +440,16 @@ define('pgadmin.browser', [
initializeBrowserTree(obj);
// Syntax highlight the SQL Pane
obj.editor = CodeMirror.fromTextArea(
document.getElementById('sql-textarea'), {
lineNumbers: true,
mode: 'text/x-pgsql',
readOnly: true,
extraKeys: pgAdmin.Browser.editor_shortcut_keys,
screenReaderLabel: gettext('SQL'),
});
if(document.getElementById('sql-textarea')){
obj.editor = CodeMirror.fromTextArea(
document.getElementById('sql-textarea'), {
lineNumbers: true,
mode: 'text/x-pgsql',
readOnly: true,
extraKeys: pgAdmin.Browser.editor_shortcut_keys,
screenReaderLabel: gettext('SQL'),
});
}
/* Cache may take time to load for the first time
* Reflect the changes once cache is available
*/
@@ -465,8 +467,8 @@ define('pgadmin.browser', [
});
setTimeout(function() {
obj.editor.setValue('-- ' + select_object_msg);
obj.editor.refresh();
obj?.editor?.setValue('-- ' + select_object_msg);
obj?.editor?.refresh();
}, 10);
// Build the treeview context menu
@@ -1086,11 +1088,13 @@ define('pgadmin.browser', [
};
if (binarySearch()) {
__ctx.t.before(i, _data).then(() => {
__ctx.t.before(i, _data).then((_item) => {
if (
__ctx.o && __ctx.o.success && typeof(__ctx.o.success) == 'function'
) {
__ctx.o.success.apply(__ctx.t, [i, _data]);
} else {
__ctx.t.select(_item);
}
}, () => {
console.warn('Failed to add before...', arguments);
@@ -1437,6 +1441,7 @@ define('pgadmin.browser', [
'_label': this.new._label,
'label': this.new.label,
});
this.t.update(ctx.i, this.new);
this.t.setLabel(ctx.i, {label: this.new.label});
this.t.addIcon(ctx.i, {icon: this.new.icon});
this.t.setId(ctx.i, {id: this.new.id});
+1 -1
View File
@@ -45,7 +45,7 @@ define([
pgAdmin.Browser.add_menus([{
name: 'refresh', node: this.type, module: this,
applies: ['object', 'context'], callback: 'refresh',
priority: 1, label: gettext('Refresh...'),
priority: 1, label: gettext('Refresh'),
icon: 'fa fa-sync-alt',
}]);
+26 -9
View File
@@ -56,11 +56,23 @@ _.extend(pgBrowser, {
}
},
restore_layout: function(docker, layout, defaultLayoutCallback) {
restore_layout: function(docker, layout, defaultLayoutCallback, checkLayout= false) {
// Try to restore the layout if there is one
if (layout != '') {
try {
docker.restore(layout);
if(checkLayout) {
// Check restore layout is restored pgAdmin 4 layout successfully if not then reset layout to default pgAdmin 4 layout.
var _panel = docker.findPanels('properties');
if(_panel.length == 0 && defaultLayoutCallback){
// clear the wcDocker before reset layout.
docker.clear();
Alertify.info(gettext('pgAdmin has detected some issues with the UI layout, so reset it to the default.'), 0);
if(defaultLayoutCallback){
defaultLayoutCallback(docker);
}
}
}
}
catch(err) {
docker.clear();
@@ -100,7 +112,10 @@ _.extend(pgBrowser, {
},
lock_layout: function(docker, op) {
let menu_items = this.menus['file']['mnu_locklayout']['menu_items'];
let menu_items = [];
if('mnu_locklayout' in this.menus['file']) {
menu_items = this.menus['file']['mnu_locklayout']['menu_items'];
}
switch(op) {
case this.lock_layout_levels.PREVENT_DOCKING:
@@ -114,13 +129,15 @@ _.extend(pgBrowser, {
break;
}
_.each(menu_items, function(menu_item) {
if(menu_item.name != ('mnu_lock_'+op)) {
menu_item.change_checked(false);
} else {
menu_item.change_checked(true);
}
});
if(menu_items) {
_.each(menu_items, function(menu_item) {
if(menu_item.name != ('mnu_lock_'+op)) {
menu_item.change_checked(false);
} else {
menu_item.change_checked(true);
}
});
}
},
save_lock_layout: function(op) {
+5 -2
View File
@@ -118,7 +118,7 @@ define('pgadmin.browser.node', [
applies: ['object', 'context'],
callback: 'refresh',
priority: 1,
label: gettext('Refresh...'),
label: gettext('Refresh'),
icon: 'fa fa-sync-alt',
}]);
@@ -838,6 +838,10 @@ define('pgadmin.browser.node', [
type: 'DELETE',
})
.done(function(res) {
if(res.success == 2){
Alertify.error(res.info, 0);
return;
}
if (res.success == 0) {
pgBrowser.report_error(res.errormsg, res.info);
} else {
@@ -867,7 +871,6 @@ define('pgadmin.browser.node', [
}
pgBrowser.report_error(
gettext('Error dropping/removing %s: "%s"', obj.label, objName), errmsg);
});
},
null
+6 -6
View File
@@ -124,14 +124,14 @@ _.extend(pgBrowser, {
if(module === 'sqleditor' || module === null || typeof module === 'undefined') {
let sqlEditPreferences = obj.get_preferences_for_module('sqleditor');
$(obj.editor.getWrapperElement()).css(
$(obj?.editor?.getWrapperElement()).css(
'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size)
);
obj.editor.setOption('tabSize', sqlEditPreferences.tab_size);
obj.editor.setOption('lineWrapping', sqlEditPreferences.wrap_code);
obj.editor.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets);
obj.editor.setOption('matchBrackets', sqlEditPreferences.brace_matching);
obj.editor.refresh();
obj?.editor?.setOption('tabSize', sqlEditPreferences.tab_size);
obj?.editor?.setOption('lineWrapping', sqlEditPreferences.wrap_code);
obj?.editor?.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets);
obj?.editor?.setOption('matchBrackets', sqlEditPreferences.brace_matching);
obj?.editor?.refresh();
}
},
@@ -47,7 +47,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
file=sys.stderr, end="")
self.test_view_data_tool_button()
print("OK.", file=sys.stderr)
#
# Check for filtered rows button
print("\nFiltered Rows ToolBar Button ",
file=sys.stderr, end="")
@@ -60,28 +60,24 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
self.test_table_name)
def test_query_tool_button(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Servers", self.server['name'],
self.server['db_password'],
self.test_db)
self.assertTrue(self.page.retry_click(
(By.CSS_SELECTOR,
BrowserToolBarLocators.open_query_tool_button_css),
(By.CSS_SELECTOR, BrowserToolBarLocators.query_tool_panel_css)),
'Query tool did not open on clicking Query Tool button.')
self.page.close_query_tool(prompt=False)
def test_view_data_tool_button(self):
self.page.click_a_tree_node(
self.test_db,
TreeAreaLocators.sub_nodes_of_databases_node(self.server['name']))
self.page.toggle_open_schema_node(
self.server['name'], self.server['db_password'],
self.test_db, 'public')
self.page.toggle_open_tables_node(
self.server['name'], self.server['db_password'],
self.test_db, 'public')
self.page.click_a_tree_node(
self.test_table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
self.page.expand_tables_node("Servers", self.server['name'],
self.server['db_password'], self.test_db,
"public")
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(self.test_table_name))
table_node.click()
self.assertTrue(self.page.retry_click(
(By.CSS_SELECTOR,
@@ -8,9 +8,11 @@
##########################################################################
import random
import time
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.feature_utils.locators import QueryToolLocators
@@ -37,9 +39,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
self.server, self.test_db, self.test_table_name)
def runTest(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Servers", self.server['name'],
self.server['db_password'],
self.test_db)
self.page.open_query_tool()
self.page.fill_codemirror_area_with(
@@ -60,8 +62,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def paste_values_to_scratch_pad(self):
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.find_element_by_tag_name("iframe"))
self.page.driver.switch_to.frame(
self.page.driver.find_element(By.TAG_NAME, "iframe"))
scratch_pad_ele = self.page.find_by_css_selector(
QueryToolLocators.scratch_pad_css)
self.page.paste_values(scratch_pad_ele)
@@ -67,9 +67,9 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
print("OK.", file=sys.stderr)
def _navigate_to_query_tool(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
self.page.open_query_tool()
def _create_new_file(self):
@@ -133,7 +133,7 @@ class KeyboardShortcutFeatureTest(BaseFeatureTest):
"and contains(.,'" + locator + "')]"
)
field = file_menu.find_element_by_name('key')
field = file_menu.find_element(By.NAME, 'key')
field.click()
field.send_keys(key)
@@ -141,5 +141,5 @@ class KeyboardShortcutFeatureTest(BaseFeatureTest):
self.page.click_modal('Save')
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".ajs-modal")
lambda driver: driver.find_element(By.CSS_SELECTOR, ".ajs-modal")
)
@@ -137,7 +137,7 @@ class PGDataypeFeatureTest(BaseFeatureTest):
self.page.click_modal('Save')
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".ajs-modal")
lambda driver: driver.find_element(By.CSS_SELECTOR, ".ajs-modal")
)
time.sleep(0.5)
@@ -154,7 +154,9 @@ class PGDataypeFeatureTest(BaseFeatureTest):
def runTest(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
self._schema_node_expandable()
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
# Check data types
self._check_datatype()
@@ -163,17 +165,15 @@ class PGDataypeFeatureTest(BaseFeatureTest):
def after(self):
self.page.remove_server(self.server)
# TODO - To be remove
def _schema_node_expandable(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
def _check_datatype(self):
# Slick grid does not render all the column if viewport is not enough
# wide. So execute test as batch of queries.
self.page.click_a_tree_node(
self.test_db,
TreeAreaLocators.sub_nodes_of_databases_node(self.server['name']))
self.page.open_query_tool()
self._create_enum_type()
for batch in config_data:
@@ -200,8 +200,8 @@ class PGDataypeFeatureTest(BaseFeatureTest):
# For every sample data-type value, check the expected output.
cnt = 2
cells = canvas.find_elements_by_css_selector(
QueryToolLocators.query_output_cells)
cells = canvas.find_elements(
By.CSS_SELECTOR, QueryToolLocators.query_output_cells)
# remove first element as it is row number.
cells.pop(0)
for val, cell, datatype in zip(
@@ -67,9 +67,9 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.wait = WebDriverWait(self.page.driver, 20)
def runTest(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.database_name)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.database_name)
# Backup
self.initiate_backup()
@@ -87,8 +87,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
(By.XPATH,
NavMenuLocators.process_watcher_alertfier))
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(
".loading-logs"), 10)
lambda driver: driver.find_element(
By.CSS_SELECTOR, ".loading-logs"), 10)
expected_backup_success_msg = "Successfully completed."
self.assertEqual(status, expected_backup_success_msg)
@@ -133,8 +133,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
(By.XPATH,
NavMenuLocators.process_watcher_alertfier))
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(
".loading-logs"), 10)
lambda driver: driver.find_element(
By.CSS_SELECTOR, ".loading-logs"), 10)
self.assertEqual(status, expected_backup_success_msg)
# Check for XSS in Restore details
@@ -209,15 +209,16 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
try:
take_bckup.click()
if self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_name(
lambda driver: driver.find_element(
By.NAME,
NavMenuLocators.backup_filename_txt_box_name)):
click = False
except Exception:
pass
def initiate_restore(self):
tools_menu = self.driver.find_element_by_link_text(
NavMenuLocators.tools_menu_link_text)
tools_menu = self.driver.find_element(
By.LINK_TEXT, NavMenuLocators.tools_menu_link_text)
tools_menu.click()
restore_obj = self.page.find_by_css_selector(
@@ -239,7 +240,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
restore_btn.click()
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(
lambda driver: driver.find_element(
By.CSS_SELECTOR,
NavMenuLocators.restore_file_name_txt_box_name))
def _check_escaped_characters(self, source_code, string_to_find, source):
@@ -286,8 +288,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
default_binary_path = self.server['default_binary_paths']
if default_binary_path is not None:
def get_server_version_string():
server_version = {130000: '13', 120000: '12', 110000: '11',
100000: '10', 90600: '9.6'}
server_version = {140000: '14', 130000: '13', 120000: '12',
110000: '11', 100000: '10', 90600: '9.6'}
for k, v in server_version.items():
if k <= self.server_information['server_version']:
return v
@@ -317,5 +319,5 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.page.click_modal('Save')
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".ajs-modal")
lambda driver: driver.find_element(By.CSS_SELECTOR, ".ajs-modal")
)
@@ -81,8 +81,8 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
self._open_maintenance_dialogue()
self.page.click_modal('OK')
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_xpath(
NavMenuLocators.maintenance_operation))
lambda driver: driver.find_element(
By.XPATH, NavMenuLocators.maintenance_operation))
# Wait for the backup status alertfier
self.wait.until(EC.visibility_of_element_located(
@@ -91,29 +91,25 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
self.verify_command()
def _open_maintenance_dialogue(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.database_name)
if self.test_level == 'table':
self.page.toggle_open_schema_node(self.server['name'],
self.server['db_password'],
self.database_name, 'public')
self.page.toggle_open_tables_node(self.server['name'],
self.server['db_password'],
self.database_name, 'public')
retry = 5
status = False
while retry > 0:
status = self.page.click_a_tree_node(
self.table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
if status:
break
else:
retry -= 1
self.assertTrue(status, "Table name {} is not selected".format(
self.table_name))
self.page.expand_tables_node("Server", self.server['name'],
self.server['db_password'],
self.database_name, 'public')
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(self.table_name))
status = False
if table_node:
status = True
self.assertTrue(status, "Table name {} is not visible/selected".
format(self.table_name))
table_node.click()
else:
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.database_name)
self.page.retry_click(
(By.LINK_TEXT,
NavMenuLocators.tools_menu_link_text),
@@ -133,8 +129,8 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
(By.XPATH,
NavMenuLocators.process_watcher_alertfier))
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(".loading-logs")
)
lambda driver: driver.find_element(
By.CSS_SELECTOR, ".loading-logs"))
if status != "Successfully completed.":
self.assertEqual(status, "Successfully completed.")
@@ -12,6 +12,7 @@ import random
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.feature_utils.locators import QueryToolLocators
@@ -55,9 +56,9 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
test_utils.create_table(self.server, self.test_db,
self.second_table_name)
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
@@ -171,7 +172,7 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
Keys.CONTROL).send_keys(Keys.SPACE).key_up(
Keys.CONTROL).perform()
if self.page.check_if_element_exist_by_xpath(
QueryToolLocators.code_mirror_hint_box_xpath, 20):
QueryToolLocators.code_mirror_hint_box_xpath, 15):
hint_displayed = True
break
else:
@@ -184,8 +185,8 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
else:
# if no IntelliSense is present it means there is only one option
# so check if required string is present in codeMirror
code_mirror = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
code_mirror = self.driver.find_elements(
By.XPATH, QueryToolLocators.code_mirror_data_xpath)
for data in code_mirror:
code_mirror_text = data.text
print("Single entry..........")
@@ -12,6 +12,7 @@ import random
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
@@ -94,7 +95,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
def _test_copies_rows(self):
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.switch_to.frame(
self.page.driver.find_element_by_tag_name("iframe"))
select_row = self.page.find_by_xpath(
@@ -106,7 +107,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
copy_row.click()
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.switch_to.frame(
self.page.driver.find_element_by_tag_name("iframe"))
scratch_pad_ele = self.page.find_by_css_selector(
@@ -121,7 +122,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
def _test_copies_columns(self):
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.switch_to.frame(
self.page.driver.find_element_by_tag_name("iframe"))
column_header = self.page.find_by_css_selector(
@@ -133,7 +134,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
copy_btn.click()
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.switch_to.frame(
self.page.driver.find_element_by_tag_name("iframe"))
scratch_pad_ele = self.page.find_by_css_selector(
@@ -169,13 +170,13 @@ class QueryToolJourneyTest(BaseFeatureTest):
failed_history_detail_pane.text
)
self.page.wait_for_elements(
lambda driver: driver.find_elements_by_css_selector(
QueryToolLocators.query_history_entries))
lambda driver: driver.find_elements(
By.CSS_SELECTOR, QueryToolLocators.query_history_entries))
# get the query history rows and click the previous query row which
# was executed and verify it
history_rows = self.driver.find_elements_by_css_selector(
QueryToolLocators.query_history_entries)
history_rows = self.driver.find_elements(
By.CSS_SELECTOR, QueryToolLocators.query_history_entries)
history_rows[1].click()
selected_history_entry = self.page.find_by_css_selector(
@@ -209,8 +210,8 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.click_tab(self.query_history_tab_name)
query_list = self.page.wait_for_elements(
lambda driver: driver.find_elements_by_css_selector(
QueryToolLocators.query_history_entries))
lambda driver: driver.find_elements(
By.CSS_SELECTOR, QueryToolLocators.query_history_entries))
self.assertTrue(17, len(query_list))
@@ -420,9 +421,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.click_modal('Yes')
def _navigate_to_query_tool(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
+17 -15
View File
@@ -36,9 +36,9 @@ class QueryToolFeatureTest(BaseFeatureTest):
def before(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.expand_database_node("Server", self.server['name'],
self.server['db_password'],
self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
self._reset_options()
@@ -128,7 +128,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
QueryToolLocators.btn_explain_buffers,
QueryToolLocators.btn_explain_timing):
btn = self.page.find_by_css_selector(op)
check = btn.find_element_by_tag_name('i')
check = btn.find_element(By.TAG_NAME, 'i')
if 'visibility-hidden' not in check.get_attribute('class'):
btn.click()
@@ -286,10 +286,10 @@ SELECT generate_series(1, 1000) as id order by id desc"""
)
# Search for 'Output' word in result (verbose option)
canvas.find_element_by_xpath("//*[contains(string(), 'Output')]")
canvas.find_element(By.XPATH, "//*[contains(string(), 'Output')]")
# Search for 'Total Cost' word in result (cost option)
canvas.find_element_by_xpath("//*[contains(string(),'Total Cost')]")
canvas.find_element(By.XPATH, "//*[contains(string(),'Total Cost')]")
def _query_tool_explain_analyze_with_buffers_and_timing(self):
query = """-- Explain analyze query with buffers and timing
@@ -382,8 +382,8 @@ SELECT relname FROM pg_catalog.pg_class
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
QueryToolLocators.output_column_data_xpath.format(table_name))
el = canvas.find_elements(By.XPATH, QueryToolLocators.
output_column_data_xpath.format(table_name))
assert len(el) == 0, "Table '{}' created with auto commit disabled " \
"and without any explicit commit.".format(
@@ -468,8 +468,9 @@ SELECT relname FROM pg_catalog.pg_class
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
QueryToolLocators.output_column_data_xpath.format(table_name))
el = canvas.find_elements(
By.XPATH, QueryToolLocators.output_column_data_xpath.format(
table_name))
assert len(el) != 0, "Table '{}' is not created with auto " \
"commit enabled.".format(table_name)
@@ -561,8 +562,9 @@ SELECT relname FROM pg_catalog.pg_class
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
QueryToolLocators.output_column_data_xpath.format(table_name))
el = canvas.find_elements(
By.XPATH, QueryToolLocators.output_column_data_xpath.format(
table_name))
assert len(el) == 0, "Table '{}' created even after ROLLBACK due to " \
"sql error.".format(table_name)
@@ -699,7 +701,7 @@ SELECT 1, pg_sleep(300)"""
QueryToolLocators.btn_explain_buffers,
QueryToolLocators.btn_explain_timing):
btn = self.page.find_by_css_selector(op)
check = btn.find_element_by_tag_name('i')
check = btn.find_element(By.TAG_NAME, 'i')
if 'visibility-hidden' not in check.get_attribute('class'):
btn.click()
# click cost button
@@ -720,7 +722,7 @@ SELECT 1, pg_sleep(300)"""
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
)
# Search for 'Output' word in result (verbose option)
canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]")
canvas.find_element(By.XPATH, "//*[contains(string(), 'JIT')]")
self.page.clear_query_tool()
@@ -732,7 +734,7 @@ class WaitForAnyElementWithText(object):
def __call__(self, driver):
try:
elements = EC._find_elements(driver, self.locator)
elements = driver.find_elements(*self.locator)
for elem in elements:
if self.text in elem.text:
return True
@@ -31,16 +31,13 @@ class TableDdlFeatureTest(BaseFeatureTest):
self.test_table_name = "test_table" + str(random.randint(1000, 3000))
test_utils.create_table(self.server, self.test_db,
self.test_table_name)
self.page.expand_tables_node("Server", self.server['name'],
self.server['db_password'], self.test_db,
'public')
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(self.test_table_name))
table_node.click()
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_tables_node(
self.server['name'], self.server['db_password'],
self.test_db, 'public')
self.page.click_a_tree_node(
self.test_table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
self.page.click_tab("SQL")
# Wait till data is displayed in SQL Tab
@@ -56,8 +56,8 @@ class CopySQLFeatureTest(BaseFeatureTest):
% self.test_table_name, 10), "No data displayed in SQL tab")
# Fetch the inner html & check for escaped characters
source_code = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
source_code = self.driver.find_elements(
By.XPATH, QueryToolLocators.code_mirror_data_xpath)
sql_query = ''
for data in source_code:
@@ -73,11 +73,11 @@ class CopySQLFeatureTest(BaseFeatureTest):
time.sleep(5)
self.driver.switch_to.default_content()
self.driver.switch_to_frame(
self.driver.find_element_by_tag_name("iframe"))
self.driver.switch_to.frame(
self.driver.find_element(By.TAG_NAME, "iframe"))
code_mirror = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
code_mirror = self.driver.find_elements(
By.XPATH, QueryToolLocators.code_mirror_data_xpath)
query_tool_result = ''
for data in code_mirror:
query_tool_result += data.text
@@ -89,16 +89,12 @@ class CopySQLFeatureTest(BaseFeatureTest):
self.test_table_name = "test_table" + str(random.randint(1000, 3000))
test_utils.create_table(self.server, self.test_db,
self.test_table_name)
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_tables_node(
self.server['name'], self.server['db_password'],
self.test_db, 'public')
self.page.click_a_tree_node(
self.test_table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
self.page.expand_tables_node("Server", self.server['name'],
self.server['db_password'], self.test_db,
'public')
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(self.test_table_name))
table_node.click()
def _update_preferences_setting(self):
file_menu = self.page.find_by_css_selector(
@@ -121,13 +121,9 @@ CREATE TABLE public.nonintpkey
def runTest(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_tables_node(self.server['name'],
self.server['db_password'],
self.test_db, 'public')
self.page.expand_tables_node("Server", self.server['name'],
self.server['db_password'], self.test_db,
'public')
self._load_config_data('table_insert_update_cases')
data_local = config_data
@@ -169,12 +165,17 @@ CREATE TABLE public.nonintpkey
config_data = config_data_json[config_key]
def _perform_test_for_table(self, table_name, config_data_local):
self.page.click_a_tree_node(
table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
# self.page.click_a_tree_node(
# table_name,
# TreeAreaLocators.sub_nodes_of_tables_node)
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(table_name))
table_node.click()
# Open Object -> View/Edit data
self._view_data_grid(table_name)
time.sleep(3)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
# Run test to insert a new row in table with default values
self._add_row(config_data_local)
@@ -237,7 +238,7 @@ CREATE TABLE public.nonintpkey
if cell_type in ['int', 'int[]']:
if value == 'clear':
cell_el.find_element_by_css_selector('input').clear()
cell_el.find_element(By.CSS_SELECTOR, 'input').clear()
else:
ActionChains(self.driver).send_keys(value). \
send_keys(Keys.ENTER).perform()
@@ -273,13 +274,13 @@ CREATE TABLE public.nonintpkey
else:
# Boolean editor test for to True click
if data[1] == 'true':
checkbox_el = cell_el.find_element_by_xpath(
".//*[contains(@class, 'multi-checkbox')]")
checkbox_el = cell_el.find_element(
By.XPATH, ".//*[contains(@class, 'multi-checkbox')]")
checkbox_el.click()
# Boolean editor test for to False click
elif data[1] == 'false':
checkbox_el = cell_el.find_element_by_xpath(
".//*[contains(@class, 'multi-checkbox')]")
checkbox_el = cell_el.find_element(
By.XPATH, ".//*[contains(@class, 'multi-checkbox')]")
# Sets true
checkbox_el.click()
# Sets false
@@ -307,7 +308,7 @@ CREATE TABLE public.nonintpkey
), CheckForViewDataTest.TIMEOUT_STRING
)
self.page.driver.switch_to.frame(
self.page.driver.find_element_by_tag_name('iframe')
self.page.driver.find_element(By.TAG_NAME, 'iframe')
)
def _copy_paste_row(self, config_data_l):
@@ -380,7 +381,7 @@ CREATE TABLE public.nonintpkey
try:
result_row = self.page.find_by_xpath(xpath)
element = \
result_row.find_element_by_class_name("r" + str(idx))
result_row.find_element(By.CLASS_NAME, "r" + str(idx))
self.page.driver.execute_script(
scroll_on_arg_for_js, element)
break
@@ -398,6 +399,6 @@ CREATE TABLE public.nonintpkey
list_item.sort(reverse=True)
for idx in list_item:
time.sleep(0.4)
element = result_row.find_element_by_class_name("r" + str(idx))
element = result_row.find_element(By.CLASS_NAME, "r" + str(idx))
self.page.driver.execute_script(
scroll_on_arg_for_js, element)
@@ -9,12 +9,14 @@
import sys
import random
import time
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from selenium.webdriver import ActionChains
from selenium.common.exceptions import StaleElementReferenceException, \
WebDriverException
from selenium.webdriver.common.by import By
from regression.feature_utils.locators import QueryToolLocators
from regression.feature_utils.tree_area_locators import TreeAreaLocators
@@ -74,7 +76,6 @@ class CheckForXssFeatureTest(BaseFeatureTest):
while retry > 0:
try:
self.page.refresh_page()
self.page.toggle_open_servers_group()
self._tables_node_expandable()
self._check_xss_in_dependents_tab()
retry = 0
@@ -106,15 +107,13 @@ class CheckForXssFeatureTest(BaseFeatureTest):
self.server, self.test_db, self.test_table_name)
def _tables_node_expandable(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_tables_node(self.server['name'],
self.server['db_password'],
self.test_db, 'public')
self.page.click_a_tree_node(
self.test_table_name,
TreeAreaLocators.sub_nodes_of_tables_node)
self.page.expand_tables_node("Server", self.server['name'],
self.server['db_password'], self.test_db,
'public')
table_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.table_node(self.test_table_name))
table_node.click()
def _check_xss_in_browser_tree(self):
print(
@@ -138,6 +137,12 @@ class CheckForXssFeatureTest(BaseFeatureTest):
file=sys.stderr, end=""
)
self.page.click_tab("SQL")
# Wait till data is displayed in SQL Tab
self.assertTrue(self.page.check_if_element_exist_by_xpath(
"//*[contains(@class,'CodeMirror-lines') and "
"contains(.,'CREATE TABLE')]", 10), "No data displayed in SQL tab")
# Fetch the inner html & check for escaped characters
source_code = self.page.find_by_xpath(
"//*[contains(@class,'CodeMirror-lines') and "
@@ -197,7 +202,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
"contains(@style, 'top:0px')]"
)
cells = result_row.find_elements_by_tag_name('div')
cells = result_row.find_elements(By.TAG_NAME, 'div')
# remove first element as it is row number.
source_code = cells[1].get_attribute('innerHTML')
@@ -239,8 +244,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
while retry > 0:
try:
history_ele = self.driver \
.find_element_by_css_selector(
".query-detail .content-value")
.find_element(By.CSS_SELECTOR,
".query-detail .content-value")
source_code = history_ele.get_attribute('innerHTML')
break
except StaleElementReferenceException:
@@ -279,8 +284,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
)
self.page.find_by_css_selector(".slick-header-column")
cells = self.driver.\
find_elements_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
@@ -310,9 +315,9 @@ class CheckForXssFeatureTest(BaseFeatureTest):
# Re-try logic
try:
ActionChains(self.driver).move_to_element(
self.driver.find_element_by_css_selector(
'div.pgadmin-explain-container > svg > g > g > image'
)
self.driver.find_element(
By.CSS_SELECTOR,
'div.pgadmin-explain-container > svg > g > g > image')
).click().perform()
break
except Exception:
@@ -326,7 +331,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
)
raise
source_code = self.driver.find_element_by_css_selector(
source_code = self.driver.find_element(
By.CSS_SELECTOR,
'.pgadmin-explain-details:not(.d-none)').get_attribute('innerHTML')
self._check_escaped_characters(
@@ -58,16 +58,12 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
self.function_name)
def _function_node_expandable(self):
self.page.expand_database_node(
self.server['name'],
self.server['db_password'], self.test_db)
self.page.toggle_open_schema_node(self.server['name'],
self.server['db_password'],
self.test_db, 'public')
self.page.toggle_open_function_node()
self.page.click_a_tree_node(
self.function_name + "()",
TreeAreaLocators.sub_nodes_of_functions_node)
self.page.expand_schema_child_node("Server", self.server['name'],
self.server['db_password'],
self.test_db, 'public', "Functions")
function_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.function_node(self.function_name + "()"))
function_node.click()
def _debug_function(self):
self.page.driver.find_element_by_link_text("Object").click()
@@ -138,7 +134,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
self._close_debugger()
def _close_debugger(self):
self.page.driver.switch_to_default_content()
self.page.driver.switch_to.default_content()
self.page.click_element(
self.page.find_by_xpath(
"//*[@id='dockerContainer']/div/div[3]/div/div[2]/div[1]")
@@ -42,6 +42,8 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
self.role)
test_utils.create_role(self.server, "postgres",
"<h1>test</h1>")
test_utils.grant_role(self.server, "postgres",
self.role, "<h1>test</h1>")
self.wait = WebDriverWait(self.page.driver, 20)
def runTest(self):
@@ -58,11 +60,13 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
"<h1>test</h1>")
def _role_node_expandable(self, role):
self.page.expand_server_node(
self.server['name'], self.server['db_password'])
self.page.toggle_open_tree_item('Login/Group Roles')
self.page.click_a_tree_node(
role, TreeAreaLocators.sub_nodes_of_login_group_node)
self.page.expand_server_child_node("Server", self.server['name'],
self.server['db_password'],
'Login/Group Roles')
role_node = self.page.check_if_element_exists_with_scroll(
TreeAreaLocators.role_node(role))
role_node.click()
def _check_role_membership_control(self):
self.page.driver.find_element_by_link_text(
@@ -70,24 +74,22 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
property_object = self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, NavMenuLocators.properties_obj_css)))
property_object.click()
WebDriverWait(self.page.driver, 4).until(
membership_tab = WebDriverWait(self.page.driver, 4).until(
EC.presence_of_element_located((
By.XPATH, "//a[normalize-space(text())='Membership']")))
self.click_membership_tab()
By.XPATH, "//span[normalize-space(text())='Membership']")))
membership_tab.click()
# Fetch the source code for our custom control
source_code = self.page.find_by_xpath(
"//div[contains(@class,'rolmembership')]"
).get_attribute('innerHTML')
"//span[contains(@class,'icon-')]/following-sibling::span"
).text
self._check_escaped_characters(
source_code,
'&lt;h1&gt;test&lt;/h1&gt;',
'Role Membership Control'
)
self.page.find_by_xpath(
"//button[contains(@type, 'cancel') and "
"contains(.,'Cancel')]"
).click()
self.page.find_by_xpath("//button/span[text()='Close']").click()
def _check_escaped_characters(self, source_code, string_to_find, source):
# For XSS we need to search against element's html code
+1224 -1127
View File
File diff suppressed because it is too large. Load diff
+6
View File
@@ -46,3 +46,9 @@
line-height: 1;
-webkit-font-smoothing: antialiased;
}
@media screen and (forced-colors: active) {
body {
forced-color-adjust: none !important;
}
}
@@ -44,6 +44,8 @@ function MappedFormControlBase({type, value, id, onChange, className, visible, i
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='int'/>;
case 'numeric':
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='numeric'/>;
case 'tel':
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props} type='tel'/>;
case 'text':
return <FormInputText name={name} value={value} onChange={onTextChange} className={className} inputRef={inputRef} {...props}/>;
case 'multiline':
+1
View File
@@ -101,6 +101,7 @@ basicSettings = createMuiTheme(basicSettings, {
},
inputMultiline: {
padding: basicSettings.spacing(0.75, 1.5),
resize: 'auto',
},
adornedEnd: {
paddingRight: basicSettings.spacing(1.5),
@@ -320,7 +320,7 @@ export const InputText = forwardRef(({
let changeVal = e.target.value;
/* For type number, we set type as tel with number regex to get validity.*/
if(['numeric', 'int'].indexOf(type) > -1) {
if(['numeric', 'int', 'tel'].indexOf(type) > -1) {
if(!e.target.validity.valid && changeVal !== '' && changeVal !== '-') {
return;
}
@@ -345,9 +345,9 @@ export const InputText = forwardRef(({
className={classes.formInput}
inputProps={{
id: cid,
maxLength: maxlength,
maxLength: controlProps?.multiline ? null : maxlength,
'aria-describedby': helpid,
...(type ? {pattern: patterns[type]} : {})
...(type ? {pattern: !_.isUndefined(controlProps) && !_.isUndefined(controlProps.pattern) ? controlProps.pattern : patterns[type]} : {})
}}
readOnly={Boolean(readonly)}
disabled={Boolean(disabled)}
@@ -327,6 +327,12 @@ import Alertify from 'pgadmin.alertifyjs';
}
};
this.resizeJsoneditorObserver = new ResizeObserver(() => {
if ($editor){
$editor.resize();
}
});
this.save = function() {
args.commitChanges();
};
@@ -352,6 +358,7 @@ import Alertify from 'pgadmin.alertifyjs';
};
this.destroy = function() {
this.resizeJsoneditorObserver.unobserve(document.getElementById('pg-json-editor'));
$editor.destroy();
$wrapper.remove();
};
@@ -408,6 +415,7 @@ import Alertify from 'pgadmin.alertifyjs';
throw(error);
}, 'jsoneditorchunk');
}
this.resizeJsoneditorObserver.observe(document.getElementById('pg-json-editor'));
};
this.serializeValue = function() {
@@ -641,6 +649,7 @@ import Alertify from 'pgadmin.alertifyjs';
};
this.destroy = function() {
this.resizeJsoneditorObserver.unobserve(document.getElementById('pg-json-editor'));
$editor.destroy();
$wrapper.remove();
};
@@ -649,6 +658,13 @@ import Alertify from 'pgadmin.alertifyjs';
$editor.focus();
};
// listen to resize event for json editor
this.resizeJsoneditorObserver = new ResizeObserver(() => {
if ($editor){
$editor.resize();
}
});
this.loadValue = function(item) {
var data = defaultValue = item[args.column.field];
tmpdata = data;
@@ -689,6 +705,7 @@ import Alertify from 'pgadmin.alertifyjs';
}, function(error){
throw(error);
}, 'jsoneditorchunk');
this.resizeJsoneditorObserver.observe(document.getElementById('pg-json-editor'));
};
this.serializeValue = function() {
+5 -5
View File
@@ -81,7 +81,7 @@ export class Tree {
}
async update(item, data) {
await this.tree.update(item, data.itemData);
await this.tree.update(item, data);
}
async remove(item) {
@@ -140,12 +140,12 @@ export class Tree {
await this.tree.toggleDirectory(item);
}
async select(item, ensureVisible=false) {
await this.tree.setActiveFile(item, ensureVisible);
async select(item, ensureVisible=false, align='auto') {
await this.tree.setActiveFile(item, ensureVisible, align);
}
async selectNode(item, ensureVisible=false) {
this.tree.setActiveFile(item, ensureVisible);
async selectNode(item, ensureVisible=false, align='auto') {
this.tree.setActiveFile(item, ensureVisible, align);
}
async unload(item) {
+3 -3
View File
@@ -30,8 +30,8 @@ export class ManageTreeNodes {
})
public updateNode = (_path, _data) => new Promise((res, rej) => {
if (_path in this.tree) {
const item = this.tree[_path];
const item = this.findNode(_path);
if (item) {
item.name = _data.label;
item.metadata.data = _data;
}
@@ -99,7 +99,7 @@ export class ManageTreeNodes {
else {
if (node.metadata.data._type.includes("coll-")) {
let _type = node.metadata.data._type.replace("coll-", "")
url = _type + '/nodes/' + _parent_url;
url = _type + '/nodes/' + _parent_url + '/';
}
else {
url = node.metadata.data._type + '/children/' + _parent_url + '/' + node.metadata.data._id;
@@ -230,7 +230,9 @@ div.jsoneditor td.jsoneditor-tree {
}
pre.jsoneditor-preview{
background-color: $color-gray-lighter !important;
background-color: $color-gray-lighter !important;
opacity: 0.8;
color: $color-fg;
}
@@ -58,7 +58,7 @@ define([
callback: 'check_func_debuggable',
category: gettext('Debugging'),
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
data: {
object: 'function',
debug_type: 'indirect',
@@ -87,7 +87,7 @@ define([
callback: 'check_func_debuggable',
category: gettext('Debugging'),
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
data: {
object: 'procedure',
debug_type: 'indirect',
@@ -101,7 +101,7 @@ define([
applies: ['object', 'context'],
callback: 'check_func_debuggable',
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
category: gettext('Debugging'),
icon: 'fa fa-arrow-circle-right',
data: {
@@ -116,7 +116,7 @@ define([
applies: ['object', 'context'],
callback: 'check_func_debuggable',
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
category: gettext('Debugging'),
icon: 'fa fa-arrow-circle-right',
data: {
@@ -146,7 +146,7 @@ define([
callback: 'check_func_debuggable',
category: gettext('Debugging'),
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
data: {
object: 'edbfunc',
debug_type: 'indirect',
@@ -175,7 +175,7 @@ define([
callback: 'check_func_debuggable',
category: gettext('Debugging'),
priority: 10,
label: gettext('Set breakpoint'),
label: gettext('Set Breakpoint'),
data: {
object: 'edbproc',
debug_type: 'indirect',
@@ -289,7 +289,7 @@ export default class SearchObjectsDialogWrapper extends DialogWrapper {
tree.findNodeWithToggle(rowData.id_path)
.then((treeItem)=>{
setTimeout(() => {
tree.select(treeItem, true);
tree.select(treeItem, true, 'center');
}, 100);
this.showMessage(null);
})
@@ -130,7 +130,7 @@ FROM (
from pg_catalog.pg_proc p
left join pg_catalog.pg_namespace n on p.pronamespace = n.oid
left join pg_catalog.pg_type t on p.prorettype = t.oid
WHERE ({{ CATALOGS.DB_SUPPORT('n') }})
WHERE ({{ CATALOGS.DB_SUPPORT('n') }}) AND NOT p.proisagg
{% endif %}
{% if all_obj %}
UNION
@@ -500,6 +500,40 @@ FROM (
JOIN pg_catalog.pg_namespace n on t.relnamespace = n.oid
where {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['aggregate'] %}
SELECT 'aggregate' AS obj_type, pr.proname AS obj_name,
':schema.'|| ns.oid || ':/' || ns.nspname || '/' || ':aggregate.' || ag.aggfnoid::oid ||':/' || pr.proname AS obj_path,
ns.nspname AS schema_name,
{{ show_node_prefs['aggregate'] }} AS show_node, pg_catalog.pg_get_function_arguments(aggfnoid::oid) AS other_info
FROM pg_aggregate ag
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=pr.pronamespace
WHERE ({{ CATALOGS.DB_SUPPORT('ns') }})
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['operator'] %}
SELECT 'operator' AS obj_type, op.oprname AS obj_name,
':schema.'|| ns.oid || ':/' || ns.nspname || '/' || ':operator.' || op.oid::oid ||':/' || op.oprname AS obj_path,
ns.nspname AS schema_name,
{{ show_node_prefs['operator'] }} AS show_node,
CASE WHEN lt.typname IS NOT NULL AND rt.typname IS NOT NULL THEN
pg_catalog.format_type(lt.oid, NULL) || ', ' || pg_catalog.format_type(rt.oid, NULL)
WHEN lt.typname IS NULL AND rt.typname IS NOT NULL THEN
pg_catalog.format_type(rt.oid, NULL)
WHEN lt.typname IS NOT NULL AND rt.typname IS NULL THEN
pg_catalog.format_type(lt.oid, NULL)
ELSE '' END AS other_info
FROM pg_catalog.pg_operator op
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=op.oprnamespace
LEFT OUTER JOIN pg_catalog.pg_type lt ON lt.oid=op.oprleft
LEFT OUTER JOIN pg_catalog.pg_type rt ON rt.oid=op.oprright
WHERE ({{ CATALOGS.DB_SUPPORT('ns') }})
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
@@ -147,7 +147,7 @@ FROM (
WHEN t.typname IN ('trigger', 'event_trigger') THEN lng.lanname NOT IN ('edbspl', 'sql', 'internal')
ELSE true
END
AND ({{ CATALOGS.DB_SUPPORT('n') }})
AND ({{ CATALOGS.DB_SUPPORT('n') }}) AND p.prokind != 'a'
{% endif %}
{% if all_obj %}
UNION
@@ -516,6 +516,40 @@ FROM (
JOIN pg_catalog.pg_namespace n on t.relnamespace = n.oid
where {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['aggregate'] %}
SELECT 'aggregate' AS obj_type, pr.proname AS obj_name,
':schema.'|| ns.oid || ':/' || ns.nspname || '/' || ':aggregate.' || ag.aggfnoid::oid ||':/' || pr.proname AS obj_path,
ns.nspname AS schema_name,
{{ show_node_prefs['aggregate'] }} AS show_node, pg_catalog.pg_get_function_arguments(aggfnoid::oid) AS other_info
FROM pg_aggregate ag
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=pr.pronamespace
WHERE ({{ CATALOGS.DB_SUPPORT('ns') }})
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['operator'] %}
SELECT 'operator' AS obj_type, op.oprname AS obj_name,
':schema.'|| ns.oid || ':/' || ns.nspname || '/' || ':operator.' || op.oid::oid ||':/' || op.oprname AS obj_path,
ns.nspname AS schema_name,
{{ show_node_prefs['operator'] }} AS show_node,
CASE WHEN lt.typname IS NOT NULL AND rt.typname IS NOT NULL THEN
pg_catalog.format_type(lt.oid, NULL) || ', ' || pg_catalog.format_type(rt.oid, NULL)
WHEN lt.typname IS NULL AND rt.typname IS NOT NULL THEN
pg_catalog.format_type(rt.oid, NULL)
WHEN lt.typname IS NOT NULL AND rt.typname IS NULL THEN
pg_catalog.format_type(lt.oid, NULL)
ELSE '' END AS other_info
FROM pg_catalog.pg_operator op
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=op.oprnamespace
LEFT OUTER JOIN pg_catalog.pg_type lt ON lt.oid=op.oprleft
LEFT OUTER JOIN pg_catalog.pg_type rt ON rt.oid=op.oprright
WHERE ({{ CATALOGS.DB_SUPPORT('ns') }})
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff. Show more