[Fix] Timeout issue while saving multilevel BOM (#13118)

diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 8cafb91..5e1e52a 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -47,7 +47,6 @@
 		self.validate_currency()
 		self.set_conversion_rate()
 		self.validate_uom_is_interger()
-		self.update_stock_qty()
 		self.set_bom_material_details()
 		self.validate_materials()
 		self.validate_operations()
@@ -247,14 +246,12 @@
 			set_default(self, "item")
 			item = frappe.get_doc("Item", self.item)
 			if item.default_bom != self.name:
-				item.default_bom = self.name
-				item.save(ignore_permissions = True)
+				frappe.db.set_value('Item', self.item, 'default_bom', self.name)
 		else:
 			frappe.db.set(self, "is_default", 0)
 			item = frappe.get_doc("Item", self.item)
 			if item.default_bom == self.name:
-				item.default_bom = None
-				item.save(ignore_permissions = True)
+				frappe.db.set_value('Item', self.item, 'default_bom', None)
 
 	def clear_operations(self):
 		if not self.with_operations:
@@ -291,6 +288,8 @@
 				m.uom = m.stock_uom
 				m.qty = m.stock_qty
 
+			m.db_update()
+
 	def validate_uom_is_interger(self):
 		from erpnext.utilities.transaction_base import validate_uom_is_integer
 		validate_uom_is_integer(self, "uom", "qty", "BOM Item")
@@ -333,19 +332,23 @@
 
 	def check_recursion(self):
 		""" Check whether recursion occurs in any bom"""
+		bom_list = self.traverse_tree()
+		bom_nos = frappe.get_all('BOM Item', fields=["bom_no"],
+			filters={'parent': ('in', bom_list), 'parenttype': 'BOM'})
 
-		check_list = [['parent', 'bom_no', 'parent'], ['bom_no', 'parent', 'child']]
-		for d in check_list:
-			bom_list, count = [self.name], 0
-			while (len(bom_list) > count ):
-				boms = frappe.db.sql(" select %s from `tabBOM Item` where %s = %s and parenttype='BOM'" %
-					(d[0], d[1], '%s'), cstr(bom_list[count]))
-				count = count + 1
-				for b in boms:
-					if b[0] == self.name:
-						frappe.throw(_("BOM recursion: {0} cannot be parent or child of {2}").format(b[0], self.name))
-					if b[0]:
-						bom_list.append(b[0])
+		raise_exception = False
+		if bom_nos and self.name in [d.bom_no for d in bom_nos]:
+			raise_exception = True
+
+		if not raise_exception:
+			bom_nos = frappe.get_all('BOM Item', fields=["parent"],
+				filters={'bom_no': self.name, 'parenttype': 'BOM'})
+
+			if self.name in [d.parent for d in bom_nos]:
+				raise_exception = True
+
+		if raise_exception:
+			frappe.throw(_("BOM recursion: {0} cannot be parent or child of {2}").format(self.name, self.name))
 
 	def update_cost_and_exploded_items(self, bom_list=[]):
 		bom_list = self.traverse_tree(bom_list)