Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

query_builder.py 8.0 KiB

12 anni fa
12 anni fa
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import webnotes
  5. out = webnotes.response
  6. from webnotes.utils import cint
  7. import webnotes.defaults
  8. def get_sql_tables(q):
  9. if q.find('WHERE') != -1:
  10. tl = q.split('FROM')[1].split('WHERE')[0].split(',')
  11. elif q.find('GROUP BY') != -1:
  12. tl = q.split('FROM')[1].split('GROUP BY')[0].split(',')
  13. else:
  14. tl = q.split('FROM')[1].split('ORDER BY')[0].split(',')
  15. return [t.strip().strip('`')[3:] for t in tl]
  16. def get_parent_dt(dt):
  17. pdt = ''
  18. if webnotes.conn.sql('select name from `tabDocType` where istable=1 and name="%s"' % dt):
  19. import webnotes.model.meta
  20. return webnotes.model.meta.get_parent_dt(dt)
  21. return pdt
  22. def get_sql_meta(tl):
  23. std_columns = {
  24. 'owner':('Owner', '', '', '100'),
  25. 'creation':('Created on', 'Date', '', '100'),
  26. 'modified':('Last modified on', 'Date', '', '100'),
  27. 'modified_by':('Modified By', '', '', '100')
  28. }
  29. meta = {}
  30. for dt in tl:
  31. meta[dt] = std_columns.copy()
  32. # for table doctype, the ID is the parent id
  33. pdt = get_parent_dt(dt)
  34. if pdt:
  35. meta[dt]['parent'] = ('ID', 'Link', pdt, '200')
  36. # get the field properties from DocField
  37. res = webnotes.conn.sql("select fieldname, label, fieldtype, options, width from tabDocField where parent='%s'" % dt)
  38. for r in res:
  39. if r[0]:
  40. meta[dt][r[0]] = (r[1], r[2], r[3], r[4]);
  41. # name
  42. meta[dt]['name'] = ('ID', 'Link', dt, '200')
  43. return meta
  44. def add_match_conditions(q, tl):
  45. sl = []
  46. ur = webnotes.user.get_roles()
  47. for dt in tl:
  48. s = getmatchcondition(dt, ur)
  49. if s:
  50. sl.append(s)
  51. # insert the conditions
  52. if sl:
  53. condition_st = q.find('WHERE')!=-1 and ' AND ' or ' WHERE '
  54. condition_end = q.find('ORDER BY')!=-1 and 'ORDER BY' or 'LIMIT'
  55. condition_end = q.find('GROUP BY')!=-1 and 'GROUP BY' or condition_end
  56. if q.find('ORDER BY')!=-1 or q.find('LIMIT')!=-1 or q.find('GROUP BY')!=-1: # if query continues beyond conditions
  57. q = q.split(condition_end)
  58. q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1]
  59. else:
  60. q = q + condition_st + '(' + ' OR '.join(sl) + ')'
  61. return q
  62. def getmatchcondition(dt, ur):
  63. res = webnotes.conn.sql("SELECT `role`, `match` FROM tabDocPerm WHERE parent = '%s' AND (`read`=1) AND permlevel = 0" % dt)
  64. cond = []
  65. for r in res:
  66. if r[0] in ur: # role applicable to user
  67. if r[1]:
  68. if ":" in r[1]:
  69. keys = r[1].split(":")
  70. else:
  71. keys = [r[1], r[1]]
  72. for d in webnotes.defaults.get_user_default_as_list(keys[0]) or ["** No Match **"]:
  73. cond.append('`tab%s`.`%s`="%s"' % (dt, r[1], d))
  74. else:
  75. return ''
  76. return ' OR '.join(cond)
  77. def exec_report(code, res, colnames=[], colwidths=[], coltypes=[], coloptions=[], filter_values={}, query='', from_export=0):
  78. col_idx, i, out, style, header_html, footer_html, page_template = {}, 0, None, [], '', '', ''
  79. for c in colnames:
  80. col_idx[c] = i
  81. i+=1
  82. # load globals (api)
  83. from webnotes import *
  84. from webnotes.utils import *
  85. from webnotes.model.doc import *
  86. set = webnotes.conn.set
  87. get_value = webnotes.conn.get_value
  88. convert_to_lists = webnotes.conn.convert_to_lists
  89. NEWLINE = '\n'
  90. exec str(code)
  91. if out!=None:
  92. res = out
  93. return res, style, header_html, footer_html, page_template
  94. def guess_type(m):
  95. """
  96. Returns fieldtype depending on the MySQLdb Description
  97. """
  98. import MySQLdb
  99. if m in MySQLdb.NUMBER:
  100. return 'Currency'
  101. elif m in MySQLdb.DATE:
  102. return 'Date'
  103. else:
  104. return 'Data'
  105. def build_description_simple():
  106. colnames, coltypes, coloptions, colwidths = [], [], [], []
  107. for m in webnotes.conn.get_description():
  108. colnames.append(m[0])
  109. coltypes.append(guess_type[m[0]])
  110. coloptions.append('')
  111. colwidths.append('100')
  112. return colnames, coltypes, coloptions, colwidths
  113. def build_description_standard(meta, tl):
  114. desc = webnotes.conn.get_description()
  115. colnames, coltypes, coloptions, colwidths = [], [], [], []
  116. # merged metadata - used if we are unable to
  117. # get both the table name and field name from
  118. # the description - in case of joins
  119. merged_meta = {}
  120. for d in meta:
  121. merged_meta.update(meta[d])
  122. for f in desc:
  123. fn, dt = f[0], ''
  124. if '.' in fn:
  125. dt, fn = fn.split('.')
  126. if (not dt) and merged_meta.get(fn):
  127. # no "AS" given, find type from merged description
  128. desc = merged_meta[fn]
  129. colnames.append(desc[0] or fn)
  130. coltypes.append(desc[1] or '')
  131. coloptions.append(desc[2] or '')
  132. colwidths.append(desc[3] or '100')
  133. elif meta.get(dt,{}).has_key(fn):
  134. # type specified for a multi-table join
  135. # usually from Report Builder
  136. desc = meta[dt][fn]
  137. colnames.append(desc[0] or fn)
  138. coltypes.append(desc[1] or '')
  139. coloptions.append(desc[2] or '')
  140. colwidths.append(desc[3] or '100')
  141. else:
  142. # nothing found
  143. # guess
  144. colnames.append(fn)
  145. coltypes.append(guess_type(f[1]))
  146. coloptions.append('')
  147. colwidths.append('100')
  148. return colnames, coltypes, coloptions, colwidths
  149. @webnotes.whitelist()
  150. def runquery(q='', ret=0, from_export=0):
  151. import webnotes.utils
  152. formatted = cint(webnotes.form_dict.get('formatted'))
  153. # CASE A: Simple Query
  154. # --------------------
  155. if webnotes.form_dict.get('simple_query') or webnotes.form_dict.get('is_simple'):
  156. if not q: q = webnotes.form_dict.get('simple_query') or webnotes.form_dict.get('query')
  157. if q.split()[0].lower() != 'select':
  158. raise Exception, 'Query must be a SELECT'
  159. as_dict = cint(webnotes.form_dict.get('as_dict'))
  160. res = webnotes.conn.sql(q, as_dict = as_dict, as_list = not as_dict, formatted=formatted)
  161. # build colnames etc from metadata
  162. colnames, coltypes, coloptions, colwidths = [], [], [], []
  163. # CASE B: Standard Query
  164. # -----------------------
  165. else:
  166. if not q: q = webnotes.form_dict.get('query')
  167. tl = get_sql_tables(q)
  168. meta = get_sql_meta(tl)
  169. q = add_match_conditions(q, tl)
  170. webnotes
  171. # replace special variables
  172. q = q.replace('__user', webnotes.session.user)
  173. q = q.replace('__today', webnotes.utils.nowdate())
  174. res = webnotes.conn.sql(q, as_list=1, formatted=formatted)
  175. colnames, coltypes, coloptions, colwidths = build_description_standard(meta, tl)
  176. # run server script
  177. # -----------------
  178. style, header_html, footer_html, page_template = '', '', '', ''
  179. out['colnames'] = colnames
  180. out['coltypes'] = coltypes
  181. out['coloptions'] = coloptions
  182. out['colwidths'] = colwidths
  183. out['header_html'] = header_html
  184. out['footer_html'] = footer_html
  185. out['page_template'] = page_template
  186. if style:
  187. out['style'] = style
  188. # just the data - return
  189. if ret==1:
  190. return res
  191. out['values'] = res
  192. # return num of entries
  193. qm = webnotes.form_dict.get('query_max') or ''
  194. if qm and qm.strip():
  195. if qm.split()[0].lower() != 'select':
  196. raise Exception, 'Query (Max) must be a SELECT'
  197. if not webnotes.form_dict.get('simple_query'):
  198. qm = add_match_conditions(qm, tl)
  199. out['n_values'] = webnotes.utils.cint(webnotes.conn.sql(qm)[0][0])
  200. @webnotes.whitelist()
  201. def runquery_csv():
  202. global out
  203. # run query
  204. res = runquery(from_export = 1)
  205. q = webnotes.form_dict.get('query')
  206. rep_name = webnotes.form_dict.get('report_name')
  207. if not webnotes.form_dict.get('simple_query'):
  208. # Report Name
  209. if not rep_name:
  210. rep_name = get_sql_tables(q)[0]
  211. if not rep_name: rep_name = 'DataExport'
  212. # Headings
  213. heads = []
  214. rows = [[rep_name], out['colnames']] + out['values']
  215. from cStringIO import StringIO
  216. import csv
  217. f = StringIO()
  218. writer = csv.writer(f)
  219. for r in rows:
  220. # encode only unicode type strings and not int, floats etc.
  221. writer.writerow(map(lambda v: isinstance(v, unicode) and v.encode('utf-8') or v, r))
  222. f.seek(0)
  223. out['result'] = unicode(f.read(), 'utf-8')
  224. out['type'] = 'csv'
  225. out['doctype'] = rep_name
  226. def add_limit_to_query(query, args):
  227. """
  228. Add limit condition to query
  229. can be used by methods called in listing to add limit condition
  230. """
  231. if args.get('limit_page_length'):
  232. query += """
  233. limit %(limit_start)s, %(limit_page_length)s"""
  234. import webnotes.utils
  235. args['limit_start'] = webnotes.utils.cint(args.get('limit_start'))
  236. args['limit_page_length'] = webnotes.utils.cint(args.get('limit_page_length'))
  237. return query, args