Add support for setting prepare threshold in server connection. #6285
parent
82fade7645
commit
10adb6a11b
Binary file not shown.
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 74 KiB |
|
@ -206,6 +206,12 @@ Use the fields in the *Advanced* tab to configure a connection:
|
||||||
the password will not expire until your pgAdmin session does.
|
the password will not expire until your pgAdmin session does.
|
||||||
Zero means the command will be executed for each new connection or reconnection that is made.
|
Zero means the command will be executed for each new connection or reconnection that is made.
|
||||||
If the generated password is not valid indefinitely, set this value to slightly before it will expire.
|
If the generated password is not valid indefinitely, set this value to slightly before it will expire.
|
||||||
|
* Use the *Prepare threshold* field to specify the number of times a query is
|
||||||
|
executed before it is prepared. If it is set to 0, every query is prepared
|
||||||
|
the first time it is executed. If it is set to blank, prepared statements are disabled
|
||||||
|
on the connection. This is particularly useful with external connection poolers,
|
||||||
|
such as PgBouncer, which is not compatible with prepared statements. Set this to
|
||||||
|
blank in such cases.
|
||||||
|
|
||||||
.. note:: The password file option is only supported when pgAdmin is using libpq
|
.. note:: The password file option is only supported when pgAdmin is using libpq
|
||||||
v10.0 or later to connect to the server.
|
v10.0 or later to connect to the server.
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
"""Add support for prepare_threshold param
|
||||||
|
https://www.psycopg.org/psycopg3/docs/advanced/prepare.html#prepared-statements
|
||||||
|
|
||||||
|
Revision ID: 44b9ce549393
|
||||||
|
Revises: 9426ad06a63b
|
||||||
|
Create Date: 2023-10-12 12:15:01.757931
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '44b9ce549393'
|
||||||
|
down_revision = '9426ad06a63b'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
with op.batch_alter_table(
|
||||||
|
"server", table_kwargs={'sqlite_autoincrement': True}) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('prepare_threshold', sa.Integer(),
|
||||||
|
nullable=True))
|
||||||
|
|
||||||
|
with op.batch_alter_table("sharedserver") as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('prepare_threshold', sa.Integer(),
|
||||||
|
nullable=True))
|
||||||
|
|
||||||
|
# get metadata from current connection
|
||||||
|
meta = sa.MetaData()
|
||||||
|
# define table representation
|
||||||
|
meta.reflect(op.get_bind(), only=('server', 'sharedserver'))
|
||||||
|
table = sa.Table('server', meta)
|
||||||
|
op.execute(
|
||||||
|
table.update().values(prepare_threshold=5)
|
||||||
|
)
|
||||||
|
table = sa.Table('sharedserver', meta)
|
||||||
|
op.execute(
|
||||||
|
table.update().values(prepare_threshold=5)
|
||||||
|
)
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# pgAdmin only upgrades, downgrade not implemented.
|
||||||
|
pass
|
|
@ -35,7 +35,6 @@ def upgrade():
|
||||||
batch_op.add_column(sa.Column('shared_username', sa.String(64), nullable=True))
|
batch_op.add_column(sa.Column('shared_username', sa.String(64), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
def downgrade():
|
||||||
# pgAdmin only upgrades, downgrade not implemented.
|
# pgAdmin only upgrades, downgrade not implemented.
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -176,6 +176,7 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||||
server.username = sharedserver.username
|
server.username = sharedserver.username
|
||||||
server.server_owner = sharedserver.server_owner
|
server.server_owner = sharedserver.server_owner
|
||||||
server.password = sharedserver.password
|
server.password = sharedserver.password
|
||||||
|
server.prepare_threshold = sharedserver.prepare_threshold
|
||||||
|
|
||||||
return server
|
return server
|
||||||
|
|
||||||
|
@ -390,7 +391,8 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||||
tunnel_authentication=0,
|
tunnel_authentication=0,
|
||||||
tunnel_identity_file=None,
|
tunnel_identity_file=None,
|
||||||
shared=True,
|
shared=True,
|
||||||
connection_params=data.connection_params
|
connection_params=data.connection_params,
|
||||||
|
prepare_threshold=data.prepare_threshold
|
||||||
)
|
)
|
||||||
db.session.add(shared_server)
|
db.session.add(shared_server)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -816,7 +818,8 @@ class ServerNode(PGChildNodeView):
|
||||||
'shared': 'shared',
|
'shared': 'shared',
|
||||||
'shared_username': 'shared_username',
|
'shared_username': 'shared_username',
|
||||||
'kerberos_conn': 'kerberos_conn',
|
'kerberos_conn': 'kerberos_conn',
|
||||||
'connection_params': 'connection_params'
|
'connection_params': 'connection_params',
|
||||||
|
'prepare_threshold': 'prepare_threshold'
|
||||||
}
|
}
|
||||||
|
|
||||||
disp_lbl = {
|
disp_lbl = {
|
||||||
|
@ -1109,7 +1112,8 @@ class ServerNode(PGChildNodeView):
|
||||||
'gss_encrypted': manager.gss_encrypted,
|
'gss_encrypted': manager.gss_encrypted,
|
||||||
'cloud_status': server.cloud_status,
|
'cloud_status': server.cloud_status,
|
||||||
'connection_params': connection_params,
|
'connection_params': connection_params,
|
||||||
'connection_string': manager.display_connection_string
|
'connection_string': manager.display_connection_string,
|
||||||
|
'prepare_threshold': server.prepare_threshold
|
||||||
}
|
}
|
||||||
|
|
||||||
return ajax_response(response)
|
return ajax_response(response)
|
||||||
|
@ -1202,7 +1206,8 @@ class ServerNode(PGChildNodeView):
|
||||||
passexec_cmd=data.get('passexec_cmd', None),
|
passexec_cmd=data.get('passexec_cmd', None),
|
||||||
passexec_expiration=data.get('passexec_expiration', None),
|
passexec_expiration=data.get('passexec_expiration', None),
|
||||||
kerberos_conn=1 if data.get('kerberos_conn', False) else 0,
|
kerberos_conn=1 if data.get('kerberos_conn', False) else 0,
|
||||||
connection_params=connection_params
|
connection_params=connection_params,
|
||||||
|
prepare_threshold=data.get('prepare_threshold', None)
|
||||||
)
|
)
|
||||||
db.session.add(server)
|
db.session.add(server)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
|
@ -344,9 +344,16 @@ export default class ServerSchema extends BaseUISchema {
|
||||||
id: 'passexec_expiration', label: gettext('Password exec expiration (seconds)'), type: 'int',
|
id: 'passexec_expiration', label: gettext('Password exec expiration (seconds)'), type: 'int',
|
||||||
group: gettext('Advanced'),
|
group: gettext('Advanced'),
|
||||||
mode: ['properties', 'edit', 'create'],
|
mode: ['properties', 'edit', 'create'],
|
||||||
visible: function(state) {
|
disabled: function(state) {
|
||||||
return !_.isEmpty(state.passexec_cmd);
|
return isEmptyString(state.passexec_cmd);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'prepare_threshold', label: gettext('Prepare threshold'), type: 'int',
|
||||||
|
group: gettext('Advanced'),
|
||||||
|
mode: ['properties', 'edit', 'create'],
|
||||||
|
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.')
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import config
|
||||||
#
|
#
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
SCHEMA_VERSION = 36
|
SCHEMA_VERSION = 37
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
#
|
#
|
||||||
|
@ -206,6 +206,7 @@ class Server(db.Model):
|
||||||
kerberos_conn = db.Column(db.Boolean(), nullable=False, default=0)
|
kerberos_conn = db.Column(db.Boolean(), nullable=False, default=0)
|
||||||
cloud_status = db.Column(db.Integer(), nullable=False, default=0)
|
cloud_status = db.Column(db.Integer(), nullable=False, default=0)
|
||||||
connection_params = db.Column(MutableDict.as_mutable(types.JSON))
|
connection_params = db.Column(MutableDict.as_mutable(types.JSON))
|
||||||
|
prepare_threshold = db.Column(db.Integer(), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class ModulePreference(db.Model):
|
class ModulePreference(db.Model):
|
||||||
|
@ -414,6 +415,7 @@ class SharedServer(db.Model):
|
||||||
tunnel_password = db.Column(PgAdminDbBinaryString())
|
tunnel_password = db.Column(PgAdminDbBinaryString())
|
||||||
shared = db.Column(db.Boolean(), nullable=False)
|
shared = db.Column(db.Boolean(), nullable=False)
|
||||||
connection_params = db.Column(MutableDict.as_mutable(types.JSON))
|
connection_params = db.Column(MutableDict.as_mutable(types.JSON))
|
||||||
|
prepare_threshold = db.Column(db.Integer(), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class Macros(db.Model):
|
class Macros(db.Model):
|
||||||
|
|
|
@ -360,12 +360,15 @@ class Connection(BaseConnection):
|
||||||
return await psycopg.AsyncConnection.connect(
|
return await psycopg.AsyncConnection.connect(
|
||||||
connection_string,
|
connection_string,
|
||||||
cursor_factory=AsyncDictCursor,
|
cursor_factory=AsyncDictCursor,
|
||||||
autocommit=autocommit)
|
autocommit=autocommit,
|
||||||
|
prepare_threshold=manager.prepare_threshold
|
||||||
|
)
|
||||||
pg_conn = asyncio.run(connectdbserver())
|
pg_conn = asyncio.run(connectdbserver())
|
||||||
else:
|
else:
|
||||||
pg_conn = psycopg.Connection.connect(
|
pg_conn = psycopg.Connection.connect(
|
||||||
connection_string,
|
connection_string,
|
||||||
cursor_factory=DictCursor)
|
cursor_factory=DictCursor,
|
||||||
|
prepare_threshold=manager.prepare_threshold)
|
||||||
|
|
||||||
except psycopg.Error as e:
|
except psycopg.Error as e:
|
||||||
manager.stop_ssh_tunnel()
|
manager.stop_ssh_tunnel()
|
||||||
|
|
|
@ -112,6 +112,7 @@ class ServerManager(object):
|
||||||
self.gss_encrypted = False
|
self.gss_encrypted = False
|
||||||
self.connection_params = server.connection_params
|
self.connection_params = server.connection_params
|
||||||
self.create_connection_string(self.db, self.user)
|
self.create_connection_string(self.db, self.user)
|
||||||
|
self.prepare_threshold = server.prepare_threshold
|
||||||
|
|
||||||
for con in self.connections:
|
for con in self.connections:
|
||||||
self.connections[con]._release()
|
self.connections[con]._release()
|
||||||
|
|
Loading…
Reference in New Issue