Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

905 řádky
28 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. # Database Module
  4. # --------------------
  5. from __future__ import unicode_literals
  6. import warnings
  7. import datetime
  8. import frappe
  9. import frappe.defaults
  10. import frappe.async
  11. import re
  12. import frappe.model.meta
  13. from frappe.utils import now, get_datetime, cstr
  14. from frappe import _
  15. from frappe.model.utils.link_count import flush_local_link_count
  16. from frappe.utils.background_jobs import execute_job, get_queue
  17. # imports - compatibility imports
  18. from six import (
  19. integer_types,
  20. string_types,
  21. binary_type,
  22. text_type,
  23. iteritems
  24. )
  25. # imports - third-party imports
  26. from markdown2 import UnicodeWithAttrs
  27. from pymysql.times import TimeDelta
  28. from pymysql.constants import ER, FIELD_TYPE
  29. from pymysql.converters import conversions
  30. import pymysql
  31. class Database:
  32. """
  33. Open a database connection with the given parmeters, if use_default is True, use the
  34. login details from `conf.py`. This is called by the request handler and is accessible using
  35. the `db` global variable. the `sql` method is also global to run queries
  36. """
  37. def __init__(self, host=None, user=None, password=None, ac_name=None, use_default = 0):
  38. self.host = host or frappe.conf.db_host or 'localhost'
  39. self.user = user or frappe.conf.db_name
  40. self._conn = None
  41. if ac_name:
  42. self.user = self.get_db_login(ac_name) or frappe.conf.db_name
  43. if use_default:
  44. self.user = frappe.conf.db_name
  45. self.transaction_writes = 0
  46. self.auto_commit_on_many_writes = 0
  47. self.password = password or frappe.conf.db_password
  48. self.value_cache = {}
  49. def get_db_login(self, ac_name):
  50. return ac_name
  51. def connect(self):
  52. """Connects to a database as set in `site_config.json`."""
  53. warnings.filterwarnings('ignore', category=pymysql.Warning)
  54. usessl = 0
  55. if frappe.conf.db_ssl_ca and frappe.conf.db_ssl_cert and frappe.conf.db_ssl_key:
  56. usessl = 1
  57. self.ssl = {
  58. 'ca':frappe.conf.db_ssl_ca,
  59. 'cert':frappe.conf.db_ssl_cert,
  60. 'key':frappe.conf.db_ssl_key
  61. }
  62. conversions.update({
  63. FIELD_TYPE.NEWDECIMAL: float,
  64. FIELD_TYPE.DATETIME: get_datetime,
  65. TimeDelta: conversions[binary_type],
  66. UnicodeWithAttrs: conversions[text_type]
  67. })
  68. if usessl:
  69. self._conn = pymysql.connect(self.host, self.user or '', self.password or '',
  70. charset='utf8mb4', use_unicode = True, ssl=self.ssl, conv = conversions)
  71. else:
  72. self._conn = pymysql.connect(self.host, self.user or '', self.password or '',
  73. charset='utf8mb4', use_unicode = True, conv = conversions)
  74. # MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1
  75. # # self._conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)
  76. self._cursor = self._conn.cursor()
  77. if self.user != 'root':
  78. self.use(self.user)
  79. frappe.local.rollback_observers = []
  80. def use(self, db_name):
  81. """`USE` db_name."""
  82. self._conn.select_db(db_name)
  83. self.cur_db_name = db_name
  84. def validate_query(self, q):
  85. """Throw exception for dangerous queries: `ALTER`, `DROP`, `TRUNCATE` if not `Administrator`."""
  86. cmd = q.strip().lower().split()[0]
  87. if cmd in ['alter', 'drop', 'truncate'] and frappe.session.user != 'Administrator':
  88. frappe.throw(_("Not permitted"), frappe.PermissionError)
  89. def sql(self, query, values=(), as_dict = 0, as_list = 0, formatted = 0,
  90. debug=0, ignore_ddl=0, as_utf8=0, auto_commit=0, update=None):
  91. """Execute a SQL query and fetch all rows.
  92. :param query: SQL query.
  93. :param values: List / dict of values to be escaped and substituted in the query.
  94. :param as_dict: Return as a dictionary.
  95. :param as_list: Always return as a list.
  96. :param formatted: Format values like date etc.
  97. :param debug: Print query and `EXPLAIN` in debug log.
  98. :param ignore_ddl: Catch exception if table, column missing.
  99. :param as_utf8: Encode values as UTF 8.
  100. :param auto_commit: Commit after executing the query.
  101. :param update: Update this dict to all rows (if returned `as_dict`).
  102. Examples:
  103. # return customer names as dicts
  104. frappe.db.sql("select name from tabCustomer", as_dict=True)
  105. # return names beginning with a
  106. frappe.db.sql("select name from tabCustomer where name like %s", "a%")
  107. # values as dict
  108. frappe.db.sql("select name from tabCustomer where name like %(name)s and owner=%(owner)s",
  109. {"name": "a%", "owner":"test@example.com"})
  110. """
  111. if not self._conn:
  112. self.connect()
  113. # in transaction validations
  114. self.check_transaction_status(query)
  115. # autocommit
  116. if auto_commit: self.commit()
  117. # execute
  118. try:
  119. if values!=():
  120. if isinstance(values, dict):
  121. values = dict(values)
  122. # MySQL-python==1.2.5 hack!
  123. if not isinstance(values, (dict, tuple, list)):
  124. values = (values,)
  125. if debug:
  126. try:
  127. self.explain_query(query, values)
  128. frappe.errprint(query % values)
  129. except TypeError:
  130. frappe.errprint([query, values])
  131. if (frappe.conf.get("logging") or False)==2:
  132. frappe.log("<<<< query")
  133. frappe.log(query)
  134. frappe.log("with values:")
  135. frappe.log(values)
  136. frappe.log(">>>>")
  137. self._cursor.execute(query, values)
  138. else:
  139. if debug:
  140. self.explain_query(query)
  141. frappe.errprint(query)
  142. if (frappe.conf.get("logging") or False)==2:
  143. frappe.log("<<<< query")
  144. frappe.log(query)
  145. frappe.log(">>>>")
  146. self._cursor.execute(query)
  147. except Exception as e:
  148. if ignore_ddl and e.args[0] in (ER.BAD_FIELD_ERROR, ER.NO_SUCH_TABLE,
  149. ER.CANT_DROP_FIELD_OR_KEY):
  150. pass
  151. # NOTE: causes deadlock
  152. # elif e.args[0]==2006:
  153. # # mysql has gone away
  154. # self.connect()
  155. # return self.sql(query=query, values=values,
  156. # as_dict=as_dict, as_list=as_list, formatted=formatted,
  157. # debug=debug, ignore_ddl=ignore_ddl, as_utf8=as_utf8,
  158. # auto_commit=auto_commit, update=update)
  159. else:
  160. raise
  161. if auto_commit: self.commit()
  162. # scrub output if required
  163. if as_dict:
  164. ret = self.fetch_as_dict(formatted, as_utf8)
  165. if update:
  166. for r in ret:
  167. r.update(update)
  168. return ret
  169. elif as_list:
  170. return self.convert_to_lists(self._cursor.fetchall(), formatted, as_utf8)
  171. elif as_utf8:
  172. return self.convert_to_lists(self._cursor.fetchall(), formatted, as_utf8)
  173. else:
  174. return self._cursor.fetchall()
  175. def explain_query(self, query, values=None):
  176. """Print `EXPLAIN` in error log."""
  177. try:
  178. frappe.errprint("--- query explain ---")
  179. if values is None:
  180. self._cursor.execute("explain " + query)
  181. else:
  182. self._cursor.execute("explain " + query, values)
  183. import json
  184. frappe.errprint(json.dumps(self.fetch_as_dict(), indent=1))
  185. frappe.errprint("--- query explain end ---")
  186. except:
  187. frappe.errprint("error in query explain")
  188. def sql_list(self, query, values=(), debug=False):
  189. """Return data as list of single elements (first column).
  190. Example:
  191. # doctypes = ["DocType", "DocField", "User", ...]
  192. doctypes = frappe.db.sql_list("select name from DocType")
  193. """
  194. return [r[0] for r in self.sql(query, values, debug=debug)]
  195. def sql_ddl(self, query, values=(), debug=False):
  196. """Commit and execute a query. DDL (Data Definition Language) queries that alter schema
  197. autocommit in MariaDB."""
  198. self.commit()
  199. self.sql(query, debug=debug)
  200. def check_transaction_status(self, query):
  201. """Raises exception if more than 20,000 `INSERT`, `UPDATE` queries are
  202. executed in one transaction. This is to ensure that writes are always flushed otherwise this
  203. could cause the system to hang."""
  204. if self.transaction_writes and \
  205. query and query.strip().split()[0].lower() in ['start', 'alter', 'drop', 'create', "begin", "truncate"]:
  206. raise Exception('This statement can cause implicit commit')
  207. if query and query.strip().lower() in ('commit', 'rollback'):
  208. self.transaction_writes = 0
  209. if query[:6].lower() in ('update', 'insert', 'delete'):
  210. self.transaction_writes += 1
  211. if self.transaction_writes > 200000:
  212. if self.auto_commit_on_many_writes:
  213. frappe.db.commit()
  214. else:
  215. frappe.throw(_("Too many writes in one request. Please send smaller requests"), frappe.ValidationError)
  216. def fetch_as_dict(self, formatted=0, as_utf8=0):
  217. """Internal. Converts results to dict."""
  218. result = self._cursor.fetchall()
  219. ret = []
  220. needs_formatting = self.needs_formatting(result, formatted)
  221. for r in result:
  222. row_dict = frappe._dict({})
  223. for i in range(len(r)):
  224. if needs_formatting:
  225. val = self.convert_to_simple_type(r[i], formatted)
  226. else:
  227. val = r[i]
  228. if as_utf8 and type(val) is text_type:
  229. val = val.encode('utf-8')
  230. row_dict[self._cursor.description[i][0]] = val
  231. ret.append(row_dict)
  232. return ret
  233. def needs_formatting(self, result, formatted):
  234. """Returns true if the first row in the result has a Date, Datetime, Long Int."""
  235. if result and result[0]:
  236. for v in result[0]:
  237. if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)):
  238. return True
  239. if formatted and isinstance(v, (int, float)):
  240. return True
  241. return False
  242. def get_description(self):
  243. """Returns result metadata."""
  244. return self._cursor.description
  245. def convert_to_simple_type(self, v, formatted=0):
  246. """Format date, time, longint values."""
  247. return v
  248. from frappe.utils import formatdate, fmt_money
  249. if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)):
  250. if isinstance(v, datetime.date):
  251. v = text_type(v)
  252. if formatted:
  253. v = formatdate(v)
  254. # time
  255. elif isinstance(v, (datetime.timedelta, datetime.datetime)):
  256. v = text_type(v)
  257. # long
  258. elif isinstance(v, integer_types):
  259. v=int(v)
  260. # convert to strings... (if formatted)
  261. if formatted:
  262. if isinstance(v, float):
  263. v=fmt_money(v)
  264. elif isinstance(v, int):
  265. v = text_type(v)
  266. return v
  267. def convert_to_lists(self, res, formatted=0, as_utf8=0):
  268. """Convert tuple output to lists (internal)."""
  269. nres = []
  270. needs_formatting = self.needs_formatting(res, formatted)
  271. for r in res:
  272. nr = []
  273. for c in r:
  274. if needs_formatting:
  275. val = self.convert_to_simple_type(c, formatted)
  276. else:
  277. val = c
  278. if as_utf8 and type(val) is text_type:
  279. val = val.encode('utf-8')
  280. nr.append(val)
  281. nres.append(nr)
  282. return nres
  283. def convert_to_utf8(self, res, formatted=0):
  284. """Encode result as UTF-8."""
  285. nres = []
  286. for r in res:
  287. nr = []
  288. for c in r:
  289. if type(c) is text_type:
  290. c = c.encode('utf-8')
  291. nr.append(self.convert_to_simple_type(c, formatted))
  292. nres.append(nr)
  293. return nres
  294. def build_conditions(self, filters):
  295. """Convert filters sent as dict, lists to SQL conditions. filter's key
  296. is passed by map function, build conditions like:
  297. * ifnull(`fieldname`, default_value) = %(fieldname)s
  298. * `fieldname` [=, !=, >, >=, <, <=] %(fieldname)s
  299. """
  300. conditions = []
  301. values = {}
  302. def _build_condition(key):
  303. """
  304. filter's key is passed by map function
  305. build conditions like:
  306. * ifnull(`fieldname`, default_value) = %(fieldname)s
  307. * `fieldname` [=, !=, >, >=, <, <=] %(fieldname)s
  308. """
  309. _operator = "="
  310. _rhs = " %(" + key + ")s"
  311. value = filters.get(key)
  312. values[key] = value
  313. if isinstance(value, (list, tuple)):
  314. # value is a tuble like ("!=", 0)
  315. _operator = value[0]
  316. values[key] = value[1]
  317. if isinstance(value[1], (tuple, list)):
  318. # value is a list in tuple ("in", ("A", "B"))
  319. inner_list = []
  320. for i, v in enumerate(value[1]):
  321. inner_key = "{0}_{1}".format(key, i)
  322. values[inner_key] = v
  323. inner_list.append("%({0})s".format(inner_key))
  324. _rhs = " ({0})".format(", ".join(inner_list))
  325. del values[key]
  326. if _operator not in ["=", "!=", ">", ">=", "<", "<=", "like", "in", "not in", "not like"]:
  327. _operator = "="
  328. if "[" in key:
  329. split_key = key.split("[")
  330. condition = "ifnull(`" + split_key[0] + "`, " + split_key[1][:-1] + ") " \
  331. + _operator + _rhs
  332. else:
  333. condition = "`" + key + "` " + _operator + _rhs
  334. conditions.append(condition)
  335. if isinstance(filters, string_types):
  336. filters = { "name": filters }
  337. for f in filters:
  338. _build_condition(f)
  339. return " and ".join(conditions), values
  340. def get(self, doctype, filters=None, as_dict=True, cache=False):
  341. """Returns `get_value` with fieldname='*'"""
  342. return self.get_value(doctype, filters, "*", as_dict=as_dict, cache=cache)
  343. def get_value(self, doctype, filters=None, fieldname="name", ignore=None, as_dict=False,
  344. debug=False, order_by=None, cache=False):
  345. """Returns a document property or list of properties.
  346. :param doctype: DocType name.
  347. :param filters: Filters like `{"x":"y"}` or name of the document. `None` if Single DocType.
  348. :param fieldname: Column name.
  349. :param ignore: Don't raise exception if table, column is missing.
  350. :param as_dict: Return values as dict.
  351. :param debug: Print query in error log.
  352. :param order_by: Column to order by
  353. Example:
  354. # return first customer starting with a
  355. frappe.db.get_value("Customer", {"name": ("like a%")})
  356. # return last login of **User** `test@example.com`
  357. frappe.db.get_value("User", "test@example.com", "last_login")
  358. last_login, last_ip = frappe.db.get_value("User", "test@example.com",
  359. ["last_login", "last_ip"])
  360. # returns default date_format
  361. frappe.db.get_value("System Settings", None, "date_format")
  362. """
  363. ret = self.get_values(doctype, filters, fieldname, ignore, as_dict, debug,
  364. order_by, cache=cache)
  365. return ((len(ret[0]) > 1 or as_dict) and ret[0] or ret[0][0]) if ret else None
  366. def get_values(self, doctype, filters=None, fieldname="name", ignore=None, as_dict=False,
  367. debug=False, order_by=None, update=None, cache=False):
  368. """Returns multiple document properties.
  369. :param doctype: DocType name.
  370. :param filters: Filters like `{"x":"y"}` or name of the document.
  371. :param fieldname: Column name.
  372. :param ignore: Don't raise exception if table, column is missing.
  373. :param as_dict: Return values as dict.
  374. :param debug: Print query in error log.
  375. :param order_by: Column to order by
  376. Example:
  377. # return first customer starting with a
  378. customers = frappe.db.get_values("Customer", {"name": ("like a%")})
  379. # return last login of **User** `test@example.com`
  380. user = frappe.db.get_values("User", "test@example.com", "*")[0]
  381. """
  382. out = None
  383. if cache and isinstance(filters, string_types) and \
  384. (doctype, filters, fieldname) in self.value_cache:
  385. return self.value_cache[(doctype, filters, fieldname)]
  386. if not order_by: order_by = 'modified desc'
  387. if isinstance(filters, list):
  388. out = self._get_value_for_many_names(doctype, filters, fieldname, debug=debug)
  389. else:
  390. fields = fieldname
  391. if fieldname!="*":
  392. if isinstance(fieldname, string_types):
  393. fields = [fieldname]
  394. else:
  395. fields = fieldname
  396. if (filters is not None) and (filters!=doctype or doctype=="DocType"):
  397. try:
  398. out = self._get_values_from_table(fields, filters, doctype, as_dict, debug, order_by, update)
  399. except Exception as e:
  400. if ignore and e.args[0] in (1146, 1054):
  401. # table or column not found, return None
  402. out = None
  403. elif (not ignore) and e.args[0]==1146:
  404. # table not found, look in singles
  405. out = self.get_values_from_single(fields, filters, doctype, as_dict, debug, update)
  406. else:
  407. raise
  408. else:
  409. out = self.get_values_from_single(fields, filters, doctype, as_dict, debug, update)
  410. if cache and isinstance(filters, string_types):
  411. self.value_cache[(doctype, filters, fieldname)] = out
  412. return out
  413. def get_values_from_single(self, fields, filters, doctype, as_dict=False, debug=False, update=None):
  414. """Get values from `tabSingles` (Single DocTypes) (internal).
  415. :param fields: List of fields,
  416. :param filters: Filters (dict).
  417. :param doctype: DocType name.
  418. """
  419. # TODO
  420. # if not frappe.model.meta.is_single(doctype):
  421. # raise frappe.DoesNotExistError("DocType", doctype)
  422. if fields=="*" or isinstance(filters, dict):
  423. # check if single doc matches with filters
  424. values = self.get_singles_dict(doctype)
  425. if isinstance(filters, dict):
  426. for key, value in filters.items():
  427. if values.get(key) != value:
  428. return []
  429. if as_dict:
  430. return values and [values] or []
  431. if isinstance(fields, list):
  432. return [map(lambda d: values.get(d), fields)]
  433. else:
  434. r = self.sql("""select field, value
  435. from tabSingles where field in (%s) and doctype=%s""" \
  436. % (', '.join(['%s'] * len(fields)), '%s'),
  437. tuple(fields) + (doctype,), as_dict=False, debug=debug)
  438. if as_dict:
  439. if r:
  440. r = frappe._dict(r)
  441. if update:
  442. r.update(update)
  443. return [r]
  444. else:
  445. return []
  446. else:
  447. return r and [[i[1] for i in r]] or []
  448. def get_singles_dict(self, doctype):
  449. """Get Single DocType as dict.
  450. :param doctype: DocType of the single object whose value is requested
  451. Example:
  452. # Get coulmn and value of the single doctype Accounts Settings
  453. account_settings = frappe.db.get_singles_dict("Accounts Settings")
  454. """
  455. return frappe._dict(self.sql("""select field, value from
  456. tabSingles where doctype=%s""", doctype))
  457. def get_all(self, *args, **kwargs):
  458. return frappe.get_all(*args, **kwargs)
  459. def get_list(self, *args, **kwargs):
  460. return frappe.get_list(*args, **kwargs)
  461. def get_single_value(self, doctype, fieldname, cache=False):
  462. """Get property of Single DocType. Cache locally by default
  463. :param doctype: DocType of the single object whose value is requested
  464. :param fieldname: `fieldname` of the property whose value is requested
  465. Example:
  466. # Get the default value of the company from the Global Defaults doctype.
  467. company = frappe.db.get_single_value('Global Defaults', 'default_company')
  468. """
  469. value = self.value_cache.setdefault(doctype, {}).get(fieldname)
  470. if value:
  471. return value
  472. val = self.sql("""select value from
  473. tabSingles where doctype=%s and field=%s""", (doctype, fieldname))
  474. val = val[0][0] if val else None
  475. if val=="0" or val=="1":
  476. # check type
  477. val = int(val)
  478. self.value_cache[doctype][fieldname] = val
  479. return val
  480. def get_singles_value(self, *args, **kwargs):
  481. """Alias for get_single_value"""
  482. return self.get_single_value(*args, **kwargs)
  483. def _get_values_from_table(self, fields, filters, doctype, as_dict, debug, order_by=None, update=None):
  484. fl = []
  485. if isinstance(fields, (list, tuple)):
  486. for f in fields:
  487. if "(" in f or " as " in f: # function
  488. fl.append(f)
  489. else:
  490. fl.append("`" + f + "`")
  491. fl = ", ".join(fl)
  492. else:
  493. fl = fields
  494. if fields=="*":
  495. as_dict = True
  496. conditions, values = self.build_conditions(filters)
  497. order_by = ("order by " + order_by) if order_by else ""
  498. r = self.sql("select {0} from `tab{1}` {2} {3} {4}"
  499. .format(fl, doctype, "where" if conditions else "", conditions, order_by), values,
  500. as_dict=as_dict, debug=debug, update=update)
  501. return r
  502. def _get_value_for_many_names(self, doctype, names, field, debug=False):
  503. names = list(filter(None, names))
  504. if names:
  505. return dict(self.sql("select name, `%s` from `tab%s` where name in (%s)" \
  506. % (field, doctype, ", ".join(["%s"]*len(names))), names, debug=debug))
  507. else:
  508. return {}
  509. def update(self, *args, **kwargs):
  510. """Update multiple values. Alias for `set_value`."""
  511. return self.set_value(*args, **kwargs)
  512. def set_value(self, dt, dn, field, val, modified=None, modified_by=None,
  513. update_modified=True, debug=False):
  514. """Set a single value in the database, do not call the ORM triggers
  515. but update the modified timestamp (unless specified not to).
  516. **Warning:** this function will not call Document events and should be avoided in normal cases.
  517. :param dt: DocType name.
  518. :param dn: Document name.
  519. :param field: Property / field name or dictionary of values to be updated
  520. :param value: Value to be updated.
  521. :param modified: Use this as the `modified` timestamp.
  522. :param modified_by: Set this user as `modified_by`.
  523. :param update_modified: default True. Set as false, if you don't want to update the timestamp.
  524. :param debug: Print the query in the developer / js console.
  525. """
  526. if not modified:
  527. modified = now()
  528. if not modified_by:
  529. modified_by = frappe.session.user
  530. to_update = {}
  531. if update_modified:
  532. to_update = {"modified": modified, "modified_by": modified_by}
  533. if isinstance(field, dict):
  534. to_update.update(field)
  535. else:
  536. to_update.update({field: val})
  537. if dn and dt!=dn:
  538. # with table
  539. conditions, values = self.build_conditions(dn)
  540. values.update(to_update)
  541. set_values = []
  542. for key in to_update:
  543. set_values.append('`{0}`=%({0})s'.format(key))
  544. self.sql("""update `tab{0}`
  545. set {1} where {2}""".format(dt, ', '.join(set_values), conditions),
  546. values, debug=debug)
  547. else:
  548. # for singles
  549. keys = to_update.keys()
  550. self.sql('''
  551. delete from tabSingles
  552. where field in ({0}) and
  553. doctype=%s'''.format(', '.join(['%s']*len(keys))),
  554. list(keys) + [dt], debug=debug)
  555. for key, value in iteritems(to_update):
  556. self.sql('''insert into tabSingles(doctype, field, value) values (%s, %s, %s)''',
  557. (dt, key, value), debug=debug)
  558. if dt in self.value_cache:
  559. del self.value_cache[dt]
  560. def set(self, doc, field, val):
  561. """Set value in document. **Avoid**"""
  562. doc.db_set(field, val)
  563. def touch(self, doctype, docname):
  564. """Update the modified timestamp of this document."""
  565. from frappe.utils import now
  566. modified = now()
  567. frappe.db.sql("""update `tab{doctype}` set `modified`=%s
  568. where name=%s""".format(doctype=doctype), (modified, docname))
  569. return modified
  570. def set_temp(self, value):
  571. """Set a temperory value and return a key."""
  572. key = frappe.generate_hash()
  573. frappe.cache().hset("temp", key, value)
  574. return key
  575. def get_temp(self, key):
  576. """Return the temperory value and delete it."""
  577. return frappe.cache().hget("temp", key)
  578. def set_global(self, key, val, user='__global'):
  579. """Save a global key value. Global values will be automatically set if they match fieldname."""
  580. self.set_default(key, val, user)
  581. def get_global(self, key, user='__global'):
  582. """Returns a global key value."""
  583. return self.get_default(key, user)
  584. def set_default(self, key, val, parent="__default", parenttype=None):
  585. """Sets a global / user default value."""
  586. frappe.defaults.set_default(key, val, parent, parenttype)
  587. def add_default(self, key, val, parent="__default", parenttype=None):
  588. """Append a default value for a key, there can be multiple default values for a particular key."""
  589. frappe.defaults.add_default(key, val, parent, parenttype)
  590. def get_default(self, key, parent="__default"):
  591. """Returns default value as a list if multiple or single"""
  592. d = self.get_defaults(key, parent)
  593. return isinstance(d, list) and d[0] or d
  594. def get_defaults(self, key=None, parent="__default"):
  595. """Get all defaults"""
  596. if key:
  597. defaults = frappe.defaults.get_defaults(parent)
  598. d = defaults.get(key, None)
  599. if(not d and key != frappe.scrub(key)):
  600. d = defaults.get(frappe.scrub(key), None)
  601. return d
  602. else:
  603. return frappe.defaults.get_defaults(parent)
  604. def begin(self):
  605. self.sql("start transaction")
  606. def commit(self):
  607. """Commit current transaction. Calls SQL `COMMIT`."""
  608. self.sql("commit")
  609. frappe.local.rollback_observers = []
  610. self.flush_realtime_log()
  611. enqueue_jobs_after_commit()
  612. flush_local_link_count()
  613. def flush_realtime_log(self):
  614. for args in frappe.local.realtime_log:
  615. frappe.async.emit_via_redis(*args)
  616. frappe.local.realtime_log = []
  617. def rollback(self):
  618. """`ROLLBACK` current transaction."""
  619. self.sql("rollback")
  620. self.begin()
  621. for obj in frappe.local.rollback_observers:
  622. if hasattr(obj, "on_rollback"):
  623. obj.on_rollback()
  624. frappe.local.rollback_observers = []
  625. def field_exists(self, dt, fn):
  626. """Return true of field exists."""
  627. return self.sql("select name from tabDocField where fieldname=%s and parent=%s", (dt, fn))
  628. def table_exists(self, tablename):
  629. """Returns True if table exists."""
  630. return ("tab" + tablename) in self.get_tables()
  631. def get_tables(self):
  632. return [d[0] for d in self.sql("show tables")]
  633. def a_row_exists(self, doctype):
  634. """Returns True if atleast one row exists."""
  635. return self.sql("select name from `tab{doctype}` limit 1".format(doctype=doctype))
  636. def exists(self, dt, dn=None):
  637. """Returns true if document exists.
  638. :param dt: DocType name.
  639. :param dn: Document name or filter dict."""
  640. if isinstance(dt, string_types):
  641. if dt!="DocType" and dt==dn:
  642. return True # single always exists (!)
  643. try:
  644. return self.get_value(dt, dn, "name")
  645. except:
  646. return None
  647. elif isinstance(dt, dict) and dt.get('doctype'):
  648. try:
  649. conditions = []
  650. for d in dt:
  651. if d == 'doctype': continue
  652. conditions.append('`%s` = "%s"' % (d, cstr(dt[d]).replace('"', '\"')))
  653. return self.sql('select name from `tab%s` where %s' % \
  654. (dt['doctype'], " and ".join(conditions)))
  655. except:
  656. return None
  657. def count(self, dt, filters=None, debug=False):
  658. """Returns `COUNT(*)` for given DocType and filters."""
  659. if filters:
  660. conditions, filters = self.build_conditions(filters)
  661. return frappe.db.sql("""select count(*)
  662. from `tab%s` where %s""" % (dt, conditions), filters, debug=debug)[0][0]
  663. else:
  664. return frappe.db.sql("""select count(*)
  665. from `tab%s`""" % (dt,))[0][0]
  666. def get_creation_count(self, doctype, minutes):
  667. """Get count of records created in the last x minutes"""
  668. from frappe.utils import now_datetime
  669. from dateutil.relativedelta import relativedelta
  670. return frappe.db.sql("""select count(name) from `tab{doctype}`
  671. where creation >= %s""".format(doctype=doctype),
  672. now_datetime() - relativedelta(minutes=minutes))[0][0]
  673. def get_db_table_columns(self, table):
  674. """Returns list of column names from given table."""
  675. return [r[0] for r in self.sql("DESC `%s`" % table)]
  676. def get_table_columns(self, doctype):
  677. """Returns list of column names from given doctype."""
  678. return self.get_db_table_columns('tab' + doctype)
  679. def has_column(self, doctype, column):
  680. """Returns True if column exists in database."""
  681. return column in self.get_table_columns(doctype)
  682. def add_index(self, doctype, fields, index_name=None):
  683. """Creates an index with given fields if not already created.
  684. Index name will be `fieldname1_fieldname2_index`"""
  685. if not index_name:
  686. index_name = "_".join(fields) + "_index"
  687. # remove index length if present e.g. (10) from index name
  688. index_name = re.sub(r"\s*\([^)]+\)\s*", r"", index_name)
  689. if not frappe.db.sql("""show index from `tab%s` where Key_name="%s" """ % (doctype, index_name)):
  690. frappe.db.commit()
  691. frappe.db.sql("""alter table `tab%s`
  692. add index `%s`(%s)""" % (doctype, index_name, ", ".join(fields)))
  693. def add_unique(self, doctype, fields, constraint_name=None):
  694. if isinstance(fields, string_types):
  695. fields = [fields]
  696. if not constraint_name:
  697. constraint_name = "unique_" + "_".join(fields)
  698. if not frappe.db.sql("""select CONSTRAINT_NAME from information_schema.TABLE_CONSTRAINTS
  699. where table_name=%s and constraint_type='UNIQUE' and CONSTRAINT_NAME=%s""",
  700. ('tab' + doctype, constraint_name)):
  701. frappe.db.commit()
  702. frappe.db.sql("""alter table `tab%s`
  703. add unique `%s`(%s)""" % (doctype, constraint_name, ", ".join(fields)))
  704. def get_system_setting(self, key):
  705. def _load_system_settings():
  706. return self.get_singles_dict("System Settings")
  707. return frappe.cache().get_value("system_settings", _load_system_settings).get(key)
  708. def close(self):
  709. """Close database connection."""
  710. if self._conn:
  711. # self._cursor.close()
  712. self._conn.close()
  713. self._cursor = None
  714. self._conn = None
  715. def escape(self, s, percent=True):
  716. """Excape quotes and percent in given string."""
  717. if isinstance(s, text_type):
  718. s = (s or "").encode("utf-8")
  719. s = text_type(pymysql.escape_string(s), "utf-8").replace("`", "\\`")
  720. # NOTE separating % escape, because % escape should only be done when using LIKE operator
  721. # or when you use python format string to generate query that already has a %s
  722. # for example: sql("select name from `tabUser` where name=%s and {0}".format(conditions), something)
  723. # defaulting it to True, as this is the most frequent use case
  724. # ideally we shouldn't have to use ESCAPE and strive to pass values via the values argument of sql
  725. if percent:
  726. s = s.replace("%", "%%")
  727. return s
  728. def enqueue_jobs_after_commit():
  729. if frappe.flags.enqueue_after_commit and len(frappe.flags.enqueue_after_commit) > 0:
  730. for job in frappe.flags.enqueue_after_commit:
  731. q = get_queue(job.get("queue"), async=job.get("async"))
  732. q.enqueue_call(execute_job, timeout=job.get("timeout"),
  733. kwargs=job.get("queue_args"))
  734. frappe.flags.enqueue_after_commit = []