diff --git a/frappe/app.py b/frappe/app.py index 822c061b67..76018e391e 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import sys, os import json import logging +import MySQLdb from werkzeug.wrappers import Request, Response from werkzeug.local import LocalManager @@ -70,6 +71,14 @@ def application(request): except Exception, e: http_status_code = getattr(e, "http_status_code", 500) + if (http_status_code==500 + and isinstance(e, MySQLdb.OperationalError) + and e.args[0] in (1205, 1213)): + # 1205 = lock wait timeout + # 1213 = deadlock + # code 409 represents conflict + http_status_code = 409 + if frappe.local.is_ajax: response = frappe.utils.response.report_error(http_status_code) else: diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index a4a8b73c09..d4e11252dd 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -82,7 +82,9 @@ def rename_parent_and_child(doctype, old, new, meta): update_child_docs(old, new, meta) def validate_rename(doctype, new, meta, merge, force, ignore_permissions): - exists = frappe.db.get_value(doctype, new) + # using for update so that it gets locked and someone else cannot edit it while this rename is going on! + exists = frappe.db.sql("select name from `tab{doctype}` where name=%s for update".format(doctype=doctype), new) + exists = exists[0][0] if exists else None if merge and not exists: frappe.msgprint(_("{0} {1} does not exist, select a new target to merge").format(doctype, new), raise_exception=1) diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js index 1618d213e5..50145a155d 100644 --- a/frappe/public/js/frappe/request.js +++ b/frappe/public/js/frappe/request.js @@ -66,6 +66,9 @@ frappe.request.call = function(opts) { msgprint(__("Not permitted")); }, + 409: function(xhr) { + msgprint(__("Another transaction is blocking this one. Please try again in a few seconds.")); + }, 417: function(data, xhr) { if(typeof data === "string") data = JSON.parse(data); opts.error_callback && opts.error_callback(data, xhr.responseText);