mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Significantly improve connection loss detection and handling in the query tool. Fixes #2815
This commit is contained in:
committed by
Dave Page
parent
c3ddb7df38
commit
e0da9c5a0c
@@ -17,7 +17,6 @@ import random
|
||||
from flask import Response, url_for, session, request, make_response
|
||||
from werkzeug.useragents import UserAgent
|
||||
from flask import current_app as app
|
||||
from flask_babel import gettext
|
||||
from flask_security import login_required
|
||||
from pgadmin.tools.sqleditor.command import *
|
||||
from pgadmin.utils import PgAdminModule
|
||||
@@ -27,6 +26,8 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.model import Server
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.exception import ConnectionLost
|
||||
|
||||
|
||||
class DataGridModule(PgAdminModule):
|
||||
@@ -93,13 +94,13 @@ def show_filter():
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/initialize/datagrid/<int:cmd_type>/<obj_type>/<int:sid>/<int:did>/'
|
||||
'<int:obj_id>',
|
||||
'/initialize/datagrid/<int:cmd_type>/<obj_type>/<int:sgid>/<int:sid>/'
|
||||
'<int:did>/<int:obj_id>',
|
||||
methods=["PUT", "POST"],
|
||||
endpoint="initialize_datagrid"
|
||||
)
|
||||
@login_required
|
||||
def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
|
||||
def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id):
|
||||
"""
|
||||
This method is responsible for creating an asynchronous connection.
|
||||
After creating the connection it will instantiate and initialize
|
||||
@@ -110,7 +111,7 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
|
||||
cmd_type: Contains value for which menu item is clicked.
|
||||
obj_type: Contains type of selected object for which data grid to
|
||||
be render
|
||||
|
||||
sgid: Server group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
obj_id: Id of currently selected object
|
||||
@@ -125,15 +126,27 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
|
||||
conn_id = str(random.randint(1, 9999999))
|
||||
try:
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
# default_conn is same connection which is created when user connect to
|
||||
# database from tree
|
||||
default_conn = manager.connection(did=did)
|
||||
conn = manager.connection(did=did, conn_id=conn_id,
|
||||
auto_reconnect=False,
|
||||
use_binary_placeholder=True,
|
||||
array_to_string=True)
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Connect the Server
|
||||
status, msg = default_conn.connect()
|
||||
if not status:
|
||||
app.logger.error(msg)
|
||||
return internal_server_error(errormsg=str(msg))
|
||||
|
||||
status, msg = conn.connect()
|
||||
if not status:
|
||||
app.logger.error(msg)
|
||||
return internal_server_error(errormsg=str(msg))
|
||||
|
||||
try:
|
||||
@@ -143,11 +156,12 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
|
||||
|
||||
# Get the object as per the object type
|
||||
command_obj = ObjectRegistry.get_object(
|
||||
obj_type, conn_id=conn_id, sid=sid,
|
||||
obj_type, conn_id=conn_id, sgid=sgid, sid=sid,
|
||||
did=did, obj_id=obj_id, cmd_type=cmd_type,
|
||||
sql_filter=filter_sql
|
||||
)
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Create a unique id for the transaction
|
||||
@@ -236,17 +250,6 @@ def panel(trans_id, is_query_tool, editor_title):
|
||||
else:
|
||||
new_browser_tab = 'false'
|
||||
|
||||
if is_query_tool == 'true':
|
||||
prompt_save_changes = pref.preference(
|
||||
'prompt_save_query_changes'
|
||||
).get()
|
||||
else:
|
||||
prompt_save_changes = pref.preference(
|
||||
'prompt_save_data_changes'
|
||||
).get()
|
||||
|
||||
display_connection_status = pref.preference('connection_status').get()
|
||||
|
||||
# Fetch the server details
|
||||
bgcolor = None
|
||||
fgcolor = None
|
||||
@@ -264,6 +267,27 @@ def panel(trans_id, is_query_tool, editor_title):
|
||||
bgcolor = s.bgcolor
|
||||
fgcolor = s.fgcolor or 'black'
|
||||
|
||||
url_params = dict()
|
||||
if is_query_tool == 'true':
|
||||
prompt_save_changes = pref.preference(
|
||||
'prompt_save_query_changes'
|
||||
).get()
|
||||
url_params['sgid'] = trans_obj.sgid
|
||||
url_params['sid'] = trans_obj.sid
|
||||
url_params['did'] = trans_obj.did
|
||||
else:
|
||||
prompt_save_changes = pref.preference(
|
||||
'prompt_save_data_changes'
|
||||
).get()
|
||||
url_params['cmd_type'] = trans_obj.cmd_type
|
||||
url_params['obj_type'] = trans_obj.object_type
|
||||
url_params['sgid'] = trans_obj.sgid
|
||||
url_params['sid'] = trans_obj.sid
|
||||
url_params['did'] = trans_obj.did
|
||||
url_params['obj_id'] = trans_obj.obj_id
|
||||
|
||||
display_connection_status = pref.preference('connection_status').get()
|
||||
|
||||
return render_template(
|
||||
"datagrid/index.html",
|
||||
_=gettext,
|
||||
@@ -281,50 +305,62 @@ def panel(trans_id, is_query_tool, editor_title):
|
||||
# convert python boolean value to equivalent js boolean literal
|
||||
# before passing it to html template.
|
||||
prompt_save_changes='true' if prompt_save_changes else 'false',
|
||||
display_connection_status=display_connection_status
|
||||
display_connection_status=display_connection_status,
|
||||
url_params=json.dumps(url_params)
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/initialize/query_tool/<int:sid>/<int:did>',
|
||||
'/initialize/query_tool/<int:sgid>/<int:sid>/<int:did>',
|
||||
methods=["POST"], endpoint='initialize_query_tool_with_did'
|
||||
)
|
||||
@blueprint.route(
|
||||
'/initialize/query_tool/<int:sid>',
|
||||
'/initialize/query_tool/<int:sgid>/<int:sid>',
|
||||
methods=["POST"], endpoint='initialize_query_tool'
|
||||
)
|
||||
@login_required
|
||||
def initialize_query_tool(sid, did=None):
|
||||
def initialize_query_tool(sgid, sid, did=None):
|
||||
"""
|
||||
This method is responsible for instantiating and initializing
|
||||
the query tool object. It will also create a unique
|
||||
transaction id and store the information into session variable.
|
||||
|
||||
Args:
|
||||
sgid: Server group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
"""
|
||||
connect = True
|
||||
if ('recreate' in request.args and
|
||||
request.args['recreate'] == '1'):
|
||||
connect = False
|
||||
# Create asynchronous connection using random connection id.
|
||||
conn_id = str(random.randint(1, 9999999))
|
||||
|
||||
# Use Maintenance database OID
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
|
||||
if did is None:
|
||||
# Use Maintenance database OID
|
||||
from pgadmin.utils.driver import get_driver
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
manager = driver.connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
if conn.connected():
|
||||
did = manager.did
|
||||
else:
|
||||
internal_server_error(
|
||||
errormsg=gettext(
|
||||
'Server disconnected. Please connect and try again.'
|
||||
)
|
||||
)
|
||||
|
||||
did = manager.did
|
||||
try:
|
||||
command_obj = ObjectRegistry.get_object(
|
||||
'query_tool', sid=sid, did=did
|
||||
'query_tool', conn_id=conn_id, sgid=sgid, sid=sid, did=did
|
||||
)
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
try:
|
||||
conn = manager.connection(did=did, conn_id=conn_id,
|
||||
auto_reconnect=False,
|
||||
use_binary_placeholder=True,
|
||||
array_to_string=True)
|
||||
if connect:
|
||||
conn.connect()
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Create a unique id for the transaction
|
||||
@@ -366,6 +402,8 @@ def close(trans_id):
|
||||
Args:
|
||||
trans_id: unique transaction id
|
||||
"""
|
||||
if 'gridData' not in session:
|
||||
return make_json_response(data={'status': True})
|
||||
|
||||
grid_data = session['gridData']
|
||||
# Return from the function if transaction id not found
|
||||
@@ -384,6 +422,7 @@ def close(trans_id):
|
||||
conn = manager.connection(
|
||||
did=cmd_obj.did, conn_id=cmd_obj.conn_id)
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Release the connection
|
||||
@@ -424,6 +463,7 @@ def validate_filter(sid, did, obj_id):
|
||||
# Call validate_filter method to validate the SQL.
|
||||
status, res = sql_filter_obj.validate_filter(filter_sql)
|
||||
except Exception as e:
|
||||
app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
return make_json_response(data={'status': status, 'result': res})
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
||||
<span class="sql-editor-busy-icon wcLoadingIcon fa fa-spinner fa-pulse"></span>
|
||||
<span class="sql-editor-busy-text wcLoadingLabel"></span>
|
||||
</div>
|
||||
<div class="sql-editor" data-trans-id="{{ uniqueId }}">
|
||||
<div class="sql-editor">
|
||||
<div id="btn-toolbar" class="pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label="">
|
||||
<div class="btn-group" role="group" aria-label="">
|
||||
<button id="btn-load-file" type="button" class="btn btn-default btn-load-file"
|
||||
@@ -361,44 +361,21 @@
|
||||
loadingDiv.addClass('hide');
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch the SQL for Scripts (eg: CREATE/UPDATE/DELETE/SELECT)
|
||||
var script_sql = '';
|
||||
{% if script_type_url%}
|
||||
// Call AJAX only if script type url is present
|
||||
$.ajax({
|
||||
url: '{{ script_type_url }}',
|
||||
type:'GET',
|
||||
async: false,
|
||||
success: function(res) {
|
||||
script_sql = res;
|
||||
},
|
||||
error: function(jqx) {
|
||||
var msg = jqx.responseText;
|
||||
/* Error from the server */
|
||||
if (jqx.status == 410 || jqx.status == 500) {
|
||||
try {
|
||||
var data = $.parseJSON(jqx.responseText);
|
||||
msg = data.errormsg;
|
||||
} catch (e) {}
|
||||
}
|
||||
pgBrowser.report_error(
|
||||
S('{{ _('Error fetching SQL for script: "%s"') }}')
|
||||
.sprintf(msg)
|
||||
.value(), msg
|
||||
);
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
{% if script_type_url %}
|
||||
var script_type_url = '{{ script_type_url }}';
|
||||
{% else %}
|
||||
var script_type_url = '';
|
||||
{% endif %}
|
||||
// Start the query tool.
|
||||
sqlEditorController.start(
|
||||
{{ uniqueId }},
|
||||
{{ is_query_tool }},
|
||||
"{{ editor_title }}",
|
||||
script_sql,
|
||||
script_type_url,
|
||||
{{ is_new_browser_tab }},
|
||||
"{{ server_type }}",
|
||||
{{ prompt_save_changes }}
|
||||
{{ prompt_save_changes }},
|
||||
{{ url_params|safe}}
|
||||
);
|
||||
});
|
||||
{% endblock %}
|
||||
|
@@ -14,7 +14,8 @@ import pickle
|
||||
import random
|
||||
import codecs
|
||||
|
||||
from flask import Response, url_for, render_template, session, request
|
||||
from flask import Response, url_for, render_template, session, request,\
|
||||
current_app
|
||||
from flask_babel import gettext
|
||||
from flask_security import login_required
|
||||
from pgadmin.tools.sqleditor.command import QueryToolCommand
|
||||
@@ -26,6 +27,7 @@ from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
|
||||
from pgadmin.misc.file_manager import Filemanager
|
||||
from pgadmin.utils.menu import MenuItem
|
||||
from pgadmin.utils.exception import ConnectionLost
|
||||
|
||||
from config import PG_DEFAULT_DRIVER, ON_DEMAND_RECORD_COUNT
|
||||
|
||||
@@ -51,13 +53,13 @@ TX_STATUS_INTRANS = 2
|
||||
TX_STATUS_INERROR = 3
|
||||
|
||||
# Connection status codes mapping
|
||||
CONNECTION_STATUS_MESSAGE_MAPPING = dict({
|
||||
0: 'The session is idle and there is no current transaction.',
|
||||
1: 'A command is currently in progress.',
|
||||
2: 'The session is idle in a valid transaction block.',
|
||||
3: 'The session is idle in a failed transaction block.',
|
||||
4: 'The connection with the server is bad.'
|
||||
})
|
||||
CONNECTION_STATUS_MESSAGE_MAPPING = dict([
|
||||
(0, 'The session is idle and there is no current transaction.'),
|
||||
(1, 'A command is currently in progress.'),
|
||||
(2, 'The session is idle in a valid transaction block.'),
|
||||
(3, 'The session is idle in a failed transaction block.'),
|
||||
(4, 'The connection with the server is bad.')
|
||||
])
|
||||
|
||||
|
||||
class SqlEditorModule(PgAdminModule):
|
||||
@@ -393,9 +395,11 @@ def check_transaction_status(trans_id):
|
||||
Returns: status and connection object
|
||||
|
||||
"""
|
||||
|
||||
if 'gridData' not in session:
|
||||
return False, unauthorized(gettext("Unauthorized request.")), \
|
||||
None, None, None
|
||||
return False, gettext(
|
||||
'Transaction ID not found in the session.'
|
||||
), None, None, None
|
||||
|
||||
grid_data = session['gridData']
|
||||
|
||||
@@ -416,18 +420,23 @@ def check_transaction_status(trans_id):
|
||||
conn = manager.connection(
|
||||
did=trans_obj.did,
|
||||
conn_id=trans_obj.conn_id,
|
||||
auto_reconnect=False,
|
||||
use_binary_placeholder=True,
|
||||
array_to_string=True
|
||||
)
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
current_app.logger.error(e)
|
||||
return False, internal_server_error(errormsg=str(e)), None, None, None
|
||||
|
||||
if conn.connected():
|
||||
return True, None, conn, trans_obj, session_obj
|
||||
else:
|
||||
return False, gettext('Not connected to server or connection with '
|
||||
'the server has been closed.'), \
|
||||
None, trans_obj, session_obj
|
||||
connect = True if 'connect' in request.args and \
|
||||
request.args['connect'] == '1' else False
|
||||
|
||||
if connect:
|
||||
conn.connect()
|
||||
|
||||
return True, None, conn, trans_obj, session_obj
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
@@ -448,12 +457,25 @@ def start_view_data(trans_id):
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
# get the default connection as current connection which is attached to
|
||||
# trans id holds the cursor which has query result so we cannot use that
|
||||
# connection to execute another query otherwise we'll lose query result.
|
||||
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
|
||||
default_conn = manager.connection(did=trans_obj.did)
|
||||
try:
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
|
||||
trans_obj.sid)
|
||||
default_conn = manager.connection(did=trans_obj.did)
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
current_app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Connect to the Server if not connected.
|
||||
if not default_conn.connected():
|
||||
@@ -465,41 +487,41 @@ def start_view_data(trans_id):
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
# set fetched row count to 0 as we are executing query again.
|
||||
trans_obj.update_fetched_row_cnt(0)
|
||||
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
|
||||
|
||||
# Fetch the sql and primary_keys from the object
|
||||
sql = trans_obj.get_sql(default_conn)
|
||||
pk_names, primary_keys = trans_obj.get_primary_keys(default_conn)
|
||||
|
||||
has_oids = False
|
||||
if trans_obj.object_type == 'table':
|
||||
# Fetch OIDs status
|
||||
has_oids = trans_obj.has_oids(default_conn)
|
||||
|
||||
# Fetch the applied filter.
|
||||
filter_applied = trans_obj.is_filter_applied()
|
||||
|
||||
# Fetch the limit for the SQL query
|
||||
limit = trans_obj.get_limit()
|
||||
|
||||
can_edit = trans_obj.can_edit()
|
||||
can_filter = trans_obj.can_filter()
|
||||
|
||||
# Store the primary keys to the session object
|
||||
session_obj['primary_keys'] = primary_keys
|
||||
|
||||
# Store the OIDs status into session object
|
||||
session_obj['has_oids'] = has_oids
|
||||
|
||||
update_session_grid_transaction(trans_id, session_obj)
|
||||
|
||||
# Execute sql asynchronously
|
||||
try:
|
||||
# set fetched row count to 0 as we are executing query again.
|
||||
trans_obj.update_fetched_row_cnt(0)
|
||||
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
|
||||
|
||||
# Fetch the sql and primary_keys from the object
|
||||
sql = trans_obj.get_sql()
|
||||
pk_names, primary_keys = trans_obj.get_primary_keys(default_conn)
|
||||
|
||||
has_oids = False
|
||||
if trans_obj.object_type == 'table':
|
||||
# Fetch OIDs status
|
||||
has_oids = trans_obj.has_oids(default_conn)
|
||||
|
||||
# Fetch the applied filter.
|
||||
filter_applied = trans_obj.is_filter_applied()
|
||||
|
||||
# Fetch the limit for the SQL query
|
||||
limit = trans_obj.get_limit()
|
||||
|
||||
can_edit = trans_obj.can_edit()
|
||||
can_filter = trans_obj.can_filter()
|
||||
|
||||
# Store the primary keys to the session object
|
||||
session_obj['primary_keys'] = primary_keys
|
||||
|
||||
# Store the OIDs status into session object
|
||||
session_obj['has_oids'] = has_oids
|
||||
|
||||
update_session_grid_transaction(trans_id, session_obj)
|
||||
|
||||
# Execute sql asynchronously
|
||||
status, result = conn.execute_async(sql)
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
else:
|
||||
status = False
|
||||
result = error_msg
|
||||
@@ -537,26 +559,24 @@ def start_query_tool(trans_id):
|
||||
else:
|
||||
sql = request.args or request.form
|
||||
|
||||
connect = True if 'connect' in request.args and \
|
||||
request.args['connect'] == '1' else False
|
||||
|
||||
if 'gridData' not in session:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'result': gettext('Transaction ID not found in the session.'),
|
||||
'can_edit': False, 'can_filter': False
|
||||
}
|
||||
)
|
||||
success=0,
|
||||
errormsg=gettext('Transaction ID not found in the session.'),
|
||||
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
|
||||
|
||||
grid_data = session['gridData']
|
||||
|
||||
# Return from the function if transaction id not found
|
||||
if str(trans_id) not in grid_data:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'result': gettext('Transaction ID not found in the session.'),
|
||||
'can_edit': False, 'can_filter': False
|
||||
}
|
||||
)
|
||||
success=0,
|
||||
errormsg=gettext('Transaction ID not found in the session.'),
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
# Fetch the object for the specified transaction id.
|
||||
# Use pickle.loads function to get the command object
|
||||
@@ -570,60 +590,55 @@ def start_query_tool(trans_id):
|
||||
|
||||
if trans_obj is not None and session_obj is not None:
|
||||
conn_id = trans_obj.conn_id
|
||||
|
||||
# if conn_id is None then we will have to create a new connection
|
||||
if conn_id is None:
|
||||
# Create asynchronous connection using random connection id.
|
||||
conn_id = str(random.randint(1, 9999999))
|
||||
|
||||
try:
|
||||
manager = get_driver(
|
||||
PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
|
||||
conn = manager.connection(did=trans_obj.did, conn_id=conn_id,
|
||||
auto_reconnect=False,
|
||||
use_binary_placeholder=True,
|
||||
array_to_string=True)
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
except Exception as e:
|
||||
current_app.logger.error(e)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Connect to the Server if not connected.
|
||||
if not conn.connected():
|
||||
if connect and not conn.connected():
|
||||
status, msg = conn.connect()
|
||||
if not status:
|
||||
current_app.logger.error(msg)
|
||||
return internal_server_error(errormsg=str(msg))
|
||||
|
||||
if conn.connected():
|
||||
# on successful connection set the connection id to the
|
||||
# transaction object
|
||||
trans_obj.set_connection_id(conn_id)
|
||||
# on successful connection set the connection id to the
|
||||
# transaction object
|
||||
trans_obj.set_connection_id(conn_id)
|
||||
|
||||
# As we changed the transaction object we need to
|
||||
# restore it and update the session variable.
|
||||
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
|
||||
update_session_grid_transaction(trans_id, session_obj)
|
||||
# As we changed the transaction object we need to
|
||||
# restore it and update the session variable.
|
||||
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
|
||||
update_session_grid_transaction(trans_id, session_obj)
|
||||
|
||||
# If auto commit is False and transaction status is Idle
|
||||
# then call is_begin_not_required() function to check BEGIN
|
||||
# is required or not.
|
||||
# If auto commit is False and transaction status is Idle
|
||||
# then call is_begin_not_required() function to check BEGIN
|
||||
# is required or not.
|
||||
|
||||
if not trans_obj.auto_commit \
|
||||
and conn.transaction_status() == TX_STATUS_IDLE \
|
||||
and is_begin_required(sql):
|
||||
conn.execute_void("BEGIN;")
|
||||
if not trans_obj.auto_commit \
|
||||
and conn.transaction_status() == TX_STATUS_IDLE \
|
||||
and is_begin_required(sql):
|
||||
conn.execute_void("BEGIN;")
|
||||
|
||||
# Execute sql asynchronously with params is None
|
||||
# and formatted_error is True.
|
||||
# Execute sql asynchronously with params is None
|
||||
# and formatted_error is True.
|
||||
try:
|
||||
status, result = conn.execute_async(sql)
|
||||
|
||||
# If the transaction aborted for some reason and
|
||||
# Auto RollBack is True then issue a rollback to cleanup.
|
||||
trans_status = conn.transaction_status()
|
||||
if trans_status == TX_STATUS_INERROR and trans_obj.auto_rollback:
|
||||
conn.execute_void("ROLLBACK;")
|
||||
else:
|
||||
status = False
|
||||
result = gettext(
|
||||
'Not connected to server or connection with the server has '
|
||||
'been closed.')
|
||||
except ConnectionLost as e:
|
||||
raise
|
||||
# If the transaction aborted for some reason and
|
||||
# Auto RollBack is True then issue a rollback to cleanup.
|
||||
trans_status = conn.transaction_status()
|
||||
if trans_status == TX_STATUS_INERROR and trans_obj.auto_rollback:
|
||||
conn.execute_void("ROLLBACK;")
|
||||
|
||||
can_edit = trans_obj.can_edit()
|
||||
can_filter = trans_obj.can_filter()
|
||||
@@ -655,10 +670,16 @@ def preferences(trans_id):
|
||||
trans_id: unique transaction id
|
||||
"""
|
||||
if request.method == 'GET':
|
||||
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
# Call the set_auto_commit and set_auto_rollback method of
|
||||
@@ -728,6 +749,13 @@ def poll(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None and session_obj is not None:
|
||||
status, result = conn.poll(
|
||||
formatted_exception_msg=True, no_result=True)
|
||||
@@ -915,6 +943,13 @@ def fetch(trans_id, fetch_all=None):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None and session_obj is not None:
|
||||
status, result = conn.async_fetchmany_2darray(fetch_row_cnt)
|
||||
if not status:
|
||||
@@ -1030,6 +1065,13 @@ def save(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1092,6 +1134,12 @@ def get_filter(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1123,6 +1171,13 @@ def apply_filter(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1159,6 +1214,13 @@ def append_filter_inclusive(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1208,6 +1270,12 @@ def append_filter_exclusive(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1255,6 +1323,13 @@ def remove_filter(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1293,6 +1368,13 @@ def set_limit(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1325,16 +1407,20 @@ def cancel_transaction(trans_id):
|
||||
trans_id: unique transaction id
|
||||
"""
|
||||
|
||||
if 'gridData' not in session:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
errormsg=gettext('Transaction ID not found in the session.'),
|
||||
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
|
||||
|
||||
grid_data = session['gridData']
|
||||
|
||||
# Return from the function if transaction id not found
|
||||
if str(trans_id) not in grid_data:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'result': gettext('Transaction ID not found in the session.')
|
||||
}
|
||||
)
|
||||
success=0,
|
||||
errormsg=gettext('Transaction ID not found in the session.'),
|
||||
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
|
||||
|
||||
# Fetch the object for the specified transaction id.
|
||||
# Use pickle.loads function to get the command object
|
||||
@@ -1403,6 +1489,13 @@ def get_object_name(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
res = trans_obj.object_name
|
||||
@@ -1433,6 +1526,13 @@ def set_auto_commit(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1475,6 +1575,13 @@ def set_auto_rollback(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1524,6 +1631,13 @@ def auto_complete(trans_id):
|
||||
# Check the transaction and connection status
|
||||
status, error_msg, conn, trans_obj, session_obj = \
|
||||
check_transaction_status(trans_id)
|
||||
|
||||
if error_msg == gettext(
|
||||
'Transaction ID not found in the session.'):
|
||||
return make_json_response(success=0, errormsg=error_msg,
|
||||
info='DATAGRID_TRANSACTION_REQUIRED',
|
||||
status=404)
|
||||
|
||||
if status and conn is not None \
|
||||
and trans_obj is not None and session_obj is not None:
|
||||
|
||||
@@ -1947,7 +2061,7 @@ def query_tool_status(trans_id):
|
||||
)
|
||||
|
||||
if conn and trans_obj and session_obj:
|
||||
status = conn.conn.get_transaction_status()
|
||||
status = conn.transaction_status()
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': status,
|
||||
|
@@ -104,7 +104,9 @@ class BaseCommand(object):
|
||||
**kwargs : N number of parameters
|
||||
"""
|
||||
|
||||
# Save the server id and database id, namespace id, object id
|
||||
# Save the server group id, server id and database id, namespace id,
|
||||
# object id
|
||||
self.sgid = kwargs['sgid'] if 'sgid' in kwargs else None
|
||||
self.sid = kwargs['sid'] if 'sid' in kwargs else None
|
||||
self.did = kwargs['did'] if 'did' in kwargs else None
|
||||
|
||||
@@ -922,7 +924,7 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
|
||||
BaseCommand.__init__(self, **kwargs)
|
||||
FetchedRowTracker.__init__(self, **kwargs)
|
||||
|
||||
self.conn_id = None
|
||||
self.conn_id = kwargs['conn_id'] if 'conn_id' in kwargs else None
|
||||
self.auto_rollback = False
|
||||
self.auto_commit = True
|
||||
|
||||
|
@@ -581,3 +581,24 @@ input.editor-checkbox:focus {
|
||||
.sql-editor .copy-all:focus {
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.ajs-body .warn-icon {
|
||||
color:#f1c40f;
|
||||
font-size: 2em;
|
||||
margin-right: 20px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.ajs-body .warn-header {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 3em;
|
||||
}
|
||||
|
||||
.ajs-body .warn-body {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ajs-body .warn-footer {
|
||||
font-size: 13px;
|
||||
line-height: 3em;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ import simplejson as json
|
||||
import re
|
||||
|
||||
from flask import render_template, request, \
|
||||
url_for, Response, abort
|
||||
url_for, Response, abort, current_app
|
||||
from flask_babel import gettext as _
|
||||
from flask_security import login_required, roles_required, current_user
|
||||
from flask_security.utils import encrypt_password
|
||||
@@ -73,7 +73,7 @@ class UserManagementModule(PgAdminModule):
|
||||
'user_management.roles', 'user_management.role',
|
||||
'user_management.update_user', 'user_management.delete_user',
|
||||
'user_management.create_user', 'user_management.users',
|
||||
'user_management.user'
|
||||
'user_management.user', current_app.login_manager.login_view
|
||||
]
|
||||
|
||||
|
||||
|
@@ -129,6 +129,95 @@ define([
|
||||
alertify.ChangePassword(title, url).resizeTo('75%', '70%');
|
||||
},
|
||||
|
||||
is_pga_login_required(xhr) {
|
||||
return xhr.status == 401 && xhr.responseJSON &&
|
||||
xhr.responseJSON.info &&
|
||||
xhr.responseJSON.info == 'PGADMIN_LOGIN_REQUIRED';
|
||||
},
|
||||
|
||||
// Callback to draw pgAdmin4 login dialog.
|
||||
pga_login: function(url) {
|
||||
var title = gettext('pgAdmin 4 login');
|
||||
url = url || url_for('security.login');
|
||||
if(!alertify.PgaLogin) {
|
||||
alertify.dialog('PgaLogin' ,function factory() {
|
||||
return {
|
||||
main: function(title, url) {
|
||||
this.set({
|
||||
'title': title,
|
||||
'url': url,
|
||||
});
|
||||
},
|
||||
build: function() {
|
||||
alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
settings:{
|
||||
url: undefined,
|
||||
},
|
||||
setup:function() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: gettext('Close'), key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
attrs:{name:'close', type:'button'},
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
//disable both padding and overflow control.
|
||||
padding : !1,
|
||||
overflow: !1,
|
||||
modal: true,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
closable: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
hooks: {
|
||||
// Triggered when the dialog is closed
|
||||
onclose: function() {
|
||||
// Clear the view
|
||||
return setTimeout((function() {
|
||||
return alertify.PgaLogin().destroy();
|
||||
}));
|
||||
},
|
||||
},
|
||||
prepare: function() {
|
||||
// create the iframe element
|
||||
var self = this,
|
||||
iframe = document.createElement('iframe'),
|
||||
url = this.setting('url');
|
||||
|
||||
iframe.onload = function() {
|
||||
var doc = this.contentDocument || this.contentWindow.document;
|
||||
if (doc.location.href.indexOf(url) == -1) {
|
||||
// login successful.
|
||||
|
||||
this.contentWindow.stop();
|
||||
this.onload = null;
|
||||
|
||||
// close the dialog.
|
||||
self.close();
|
||||
pgBrowser.Events.trigger('pgadmin:user:logged-in');
|
||||
}
|
||||
};
|
||||
|
||||
iframe.frameBorder = 'no';
|
||||
iframe.width = '100%';
|
||||
iframe.height = '100%';
|
||||
iframe.src = url;
|
||||
// add it to the dialog
|
||||
self.elements.content.appendChild(iframe);
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
alertify.PgaLogin(title, url).resizeTo('75%','70%');
|
||||
},
|
||||
|
||||
// Callback to draw User Management Dialog.
|
||||
show_users: function() {
|
||||
if (!userInfo['is_admin']) return;
|
||||
|
Reference in New Issue
Block a user