diff --git a/docs/en_US/images/server_advanced.png b/docs/en_US/images/server_advanced.png index a65e98ede..fcc27187e 100644 Binary files a/docs/en_US/images/server_advanced.png and b/docs/en_US/images/server_advanced.png differ diff --git a/docs/en_US/images/server_connection.png b/docs/en_US/images/server_connection.png index 4229a853e..910f9252a 100644 Binary files a/docs/en_US/images/server_connection.png and b/docs/en_US/images/server_connection.png differ diff --git a/docs/en_US/images/server_general.png b/docs/en_US/images/server_general.png index c5bcbe52a..b446fd421 100644 Binary files a/docs/en_US/images/server_general.png and b/docs/en_US/images/server_general.png differ diff --git a/docs/en_US/images/server_parameters.png b/docs/en_US/images/server_parameters.png index e9f5868e0..58313e783 100644 Binary files a/docs/en_US/images/server_parameters.png and b/docs/en_US/images/server_parameters.png differ diff --git a/docs/en_US/images/server_post_connection_sql.png b/docs/en_US/images/server_post_connection_sql.png new file mode 100644 index 000000000..d5cb5a766 Binary files /dev/null and b/docs/en_US/images/server_post_connection_sql.png differ diff --git a/docs/en_US/images/server_ssh_tunnel.png b/docs/en_US/images/server_ssh_tunnel.png index 68df1368d..71e9e806e 100644 Binary files a/docs/en_US/images/server_ssh_tunnel.png and b/docs/en_US/images/server_ssh_tunnel.png differ diff --git a/docs/en_US/images/server_tags.png b/docs/en_US/images/server_tags.png index ac849664f..e2a4538a3 100644 Binary files a/docs/en_US/images/server_tags.png and b/docs/en_US/images/server_tags.png differ diff --git a/docs/en_US/release_notes_9_2.rst b/docs/en_US/release_notes_9_2.rst index 5dc7c6a39..6dc467ff6 100644 --- a/docs/en_US/release_notes_9_2.rst +++ b/docs/en_US/release_notes_9_2.rst @@ -21,6 +21,7 @@ New features ************ | `Issue #4194 `_ - Added support to automatically open a file after it is downloaded in the desktop mode. + | `Issue #4503 `_ - Added support for post-connection SQL execution, which will be run automatically on each connection made to any database of the server. | `Issue #5871 `_ - Add support for restoring plain SQL database dumps. | `Issue #8034 `_ - Added support for creating Directory nodes in EPAS. | `Issue #8449 `_ - Change icon buttons to show tooltip even when disabled. @@ -34,6 +35,7 @@ Bug fixes ********* | `Issue #8006 `_ - Removed the pre-install script from the Red Hat build function as it was causing a No such file or directory warning during the update. + | `Issue #8316 `_ - Ensure that modal dialogs are not triggered more than once to avoid duplicates. | `Issue #8355 `_ - Change session files garbage collection strategy. | `Issue #8437 `_ - Fixed an issue where the PSQL terminal displays keyname for non alphanumeric keys. | `Issue #8462 `_ - Fixed an issue where geometries in the geometry viewer will render partially when the container was resized. diff --git a/docs/en_US/server_dialog.rst b/docs/en_US/server_dialog.rst index 92a2d19f6..eed3faf0c 100644 --- a/docs/en_US/server_dialog.rst +++ b/docs/en_US/server_dialog.rst @@ -225,14 +225,14 @@ Use the fields in the *Advanced* tab to configure a connection: .. note:: The Password exec option is only supported when pgAdmin is run in desktop mode. -* Click the *Save* button to save your work. -* Click the *Close* button to exit without saving your work. -* Click the *Reset* button to return the values specified on the Server dialog - to their original condition. +Click the *Post Connection SQL* tab to continue. -.. toctree:: +.. image:: images/server_post_connection_sql.png + :alt: Server dialog post connection sql tab + :align: center - clear_saved_passwords +* Use the *Post Connection SQL* field to write the SQL queries that will be + executed in autocommit mode for each connection made to any database on this server. Click the *Tags* tab to continue. @@ -245,6 +245,15 @@ Use the table in the *Tags* tab to add tags. The tags will be shown on the right a server node label in the object explorer tree. Click on the *+* button to add a new tag. Some of the parameters are: + * *Text* field to specify the tag name. + * *Color* field to select the accent color of the tag. -* *Text* field to specify the tag name. -* *Color* field to select the accent color of the tag. + +* Click the *Save* button to save your work. +* Click the *Close* button to exit without saving your work. +* Click the *Reset* button to return the values specified on the Server dialog + to their original condition. + +.. toctree:: + + clear_saved_passwords \ No newline at end of file diff --git a/web/migrations/versions/e982c040d9b5_.py b/web/migrations/versions/e982c040d9b5_.py new file mode 100644 index 000000000..64c89d303 --- /dev/null +++ b/web/migrations/versions/e982c040d9b5_.py @@ -0,0 +1,33 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2025, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +""" + +Revision ID: e982c040d9b5 +Revises: 255e2842e4d7 +Create Date: 2025-03-13 16:55:26.893395 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = 'e982c040d9b5' +down_revision = '255e2842e4d7' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('server', sa.Column('post_connection_sql', sa.String())) + + +def downgrade(): + # pgAdmin only upgrades, downgrade not implemented. + pass diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index de333bc27..33b1a3d61 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -763,7 +763,8 @@ class ServerNode(PGChildNodeView): 'kerberos_conn': 'kerberos_conn', 'connection_params': 'connection_params', 'prepare_threshold': 'prepare_threshold', - 'tags': 'tags' + 'tags': 'tags', + 'post_connection_sql': 'post_connection_sql' } disp_lbl = { @@ -1053,6 +1054,7 @@ class ServerNode(PGChildNodeView): 'connection_string': display_connection_str, 'prepare_threshold': server.prepare_threshold, 'tags': tags, + 'post_connection_sql': server.post_connection_sql, } return ajax_response(response) @@ -1169,7 +1171,8 @@ class ServerNode(PGChildNodeView): kerberos_conn=1 if data.get('kerberos_conn', False) else 0, connection_params=connection_params, prepare_threshold=data.get('prepare_threshold', None), - tags=data.get('tags', None) + tags=data.get('tags', None), + post_connection_sql=data.get('post_connection_sql', None) ) db.session.add(server) db.session.commit() @@ -1585,6 +1588,7 @@ class ServerNode(PGChildNodeView): return make_json_response( success=1, + errormsg=errmsg, info=gettext("Server connected."), data={ "sid": server.id, diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js index 86014740a..573bc7e25 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js @@ -697,6 +697,13 @@ define('pgadmin.node.server', [ To make sure all the menus for database is in the right state */ pgBrowser.enable_disable_menus(_item); + /* Below code is added to show the error message if + connection is successful, but there is an error to + run the post connection sql queries. */ + if (res?.errormsg) { + pgAdmin.Browser.notifier.error(res.errormsg, null); + } + // We're not reconnecting if (!_wasConnected) { _tree.setInode(_item); diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.ui.js b/web/pgadmin/browser/server_groups/servers/static/js/server.ui.js index 63b70228d..862c09849 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.ui.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.ui.js @@ -489,6 +489,14 @@ export default class ServerSchema extends BaseUISchema { helpMessageMode: ['edit', 'create'], helpMessage: gettext('If it is set to 0, every query is prepared the first time it is executed. If it is set to blank, prepared statements are disabled on the connection.') }, + { + id: 'post_connection_sql', label: gettext('Post Connection SQL'), + group: gettext('Post Connection SQL'), + mode: ['properties', 'edit', 'create'], + type: 'sql', isFullTab: true, + readonly: obj.isConnected, + helpMessage: gettext('Any query specified in the control below will be executed with autocommit mode enabled for each connection to any database on this server.'), + }, { id: 'tags', label: gettext('Tags'), type: 'collection', group: gettext('Tags'), diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py index c59cb3a94..c8f7fd899 100644 --- a/web/pgadmin/model/__init__.py +++ b/web/pgadmin/model/__init__.py @@ -33,7 +33,7 @@ import config # ########################################################################## -SCHEMA_VERSION = 42 +SCHEMA_VERSION = 43 ########################################################################## # @@ -215,6 +215,7 @@ class Server(db.Model): db.CheckConstraint('is_adhoc >= 0 AND is_adhoc <= 1'), nullable=False, default=0 ) + post_connection_sql = db.Column(db.String(), nullable=True) def clone(self): d = dict(self.__dict__) diff --git a/web/pgadmin/utils/driver/psycopg3/connection.py b/web/pgadmin/utils/driver/psycopg3/connection.py index cc10ebd76..d72736ebb 100644 --- a/web/pgadmin/utils/driver/psycopg3/connection.py +++ b/web/pgadmin/utils/driver/psycopg3/connection.py @@ -600,9 +600,11 @@ WHERE db.datname = current_database()""") self._set_server_type_and_password(kwargs, manager) + ret_msg = self.execute_post_connection_sql(cur, manager) + manager.update_session() - return True, None + return True, ret_msg def _set_user_info(self, cur, manager, **kwargs): """ @@ -669,6 +671,18 @@ WHERE db.datname = current_database()""") manager.server_cls = st break + def execute_post_connection_sql(self, cur, manager): + # Execute post connection SQL if provided in the server dialog + errmsg = None + if manager.post_connection_sql and manager.post_connection_sql != '': + status = self._execute(cur, manager.post_connection_sql) + if status is not None: + errmsg = gettext(("Failed to execute the post connection SQL " + "with below error message:\n{msg}").format( + msg=status)) + current_app.logger.error(errmsg) + return errmsg + def __cursor(self, server_cursor=False, scrollable=False): if not get_crypt_key()[0] and config.SERVER_MODE: diff --git a/web/pgadmin/utils/driver/psycopg3/server_manager.py b/web/pgadmin/utils/driver/psycopg3/server_manager.py index f2555ca18..dbd784da1 100644 --- a/web/pgadmin/utils/driver/psycopg3/server_manager.py +++ b/web/pgadmin/utils/driver/psycopg3/server_manager.py @@ -116,6 +116,7 @@ class ServerManager(object): self.connection_params = server.connection_params self.create_connection_string(self.db, self.user) self.prepare_threshold = server.prepare_threshold + self.post_connection_sql = server.post_connection_sql for con in self.connections: self.connections[con]._release()