sqlbuilder.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. """
  2. MODULE: sqlbuilder.py
  3. CLASSES:
  4. * SQLFrame
  5. PURPOSE: GRASS SQL Builder
  6. Usage:
  7. sqlbuilder.py table_name
  8. AUTHOR(S): GRASS Development Team
  9. Original author: Jachym Cepicky <jachym.cepicky gmail.com>
  10. Various updates: Martin Landa <landa.martin gmail.com>
  11. COPYRIGHT: (C) 2007 by the GRASS Development Team
  12. This program is free software under the GNU General Public
  13. License (>=v2). Read the file COPYING that comes with GRASS
  14. for details.
  15. """
  16. import wx
  17. import os,sys
  18. import time
  19. import grassenv
  20. import gcmd
  21. import globalvar
  22. imagePath = os.path.join(globalvar.ETCWXDIR)
  23. sys.path.append(imagePath)
  24. import images
  25. imagepath = images.__path__[0]
  26. sys.path.append(imagepath)
  27. class SQLFrame(wx.Frame):
  28. """SQL Frame class"""
  29. def __init__(self, parent, id, title, vectmap, qtype="select"):
  30. wx.Frame.__init__(self, parent, id, title)
  31. self.SetTitle(_("GRASS SQL Builder: %s") % (qtype.upper()))
  32. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
  33. #
  34. # variables
  35. #
  36. self.vectmap = vectmap
  37. if not "@" in self.vectmap:
  38. self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable ("MAPSET")
  39. self.mapname, self.mapset = self.vectmap.split("@")
  40. self.layer,self.tablename, self.column, self.database, self.driver =\
  41. os.popen("v.db.connect -g map=%s" %\
  42. (self.vectmap)).readlines()[0].strip().split()
  43. self.qtype = qtype # type of the uqery: SELECT, UPDATE, DELETE, ...
  44. self.column_names = [] # array with column names
  45. self.columns = {} # array with colum properties
  46. self.colvalues = [] # arrya with uniqe values in selected column
  47. self.heading = ""
  48. self.parent = parent
  49. if self.qtype.lower()=="select":
  50. self.heading = "SELECT * FROM %s WHERE" % self.tablename
  51. # Init
  52. self.GetColumns()
  53. #
  54. # Buttons
  55. #
  56. self.btn_clear = wx.Button(self, -1, "Clear")
  57. self.btn_verify = wx.Button(self, -1, "Verify")
  58. #self.btn_help = wx.Button(self, -1, "Help")
  59. # self.btn_load = wx.Button(self, -1, "Load")
  60. # self.btn_save = wx.Button(self, -1, "Save")
  61. self.btn_apply = wx.Button(self, -1, "Apply")
  62. self.btn_close = wx.Button(self, -1, "Close")
  63. self.btn_uniqe = wx.Button(self, -1, "Get all values")
  64. self.btn_uniqesample = wx.Button(self, -1, "Get sample")
  65. self.btn_is = wx.Button(self, -1, "=")
  66. self.btn_isnot = wx.Button(self, -1, "!=")
  67. self.btn_like = wx.Button(self, -1, "LIKE")
  68. self.btn_gt = wx.Button(self, -1, ">=")
  69. self.btn_gtis = wx.Button(self, -1, ">")
  70. self.btn_lt = wx.Button(self, -1, "<=")
  71. self.btn_ltis = wx.Button(self, -1, "<")
  72. self.btn_or = wx.Button(self, -1, "OR")
  73. self.btn_not = wx.Button(self, -1, "NOT")
  74. self.btn_and = wx.Button(self, -1, "AND")
  75. self.btn_brackets = wx.Button(self, -1, "()")
  76. self.btn_prc = wx.Button(self, -1, "%")
  77. #
  78. # Text labels
  79. #
  80. #self.label_headding = wx.StaticText(self, -1, '')
  81. #
  82. # Textareas
  83. #
  84. self.text_sql = wx.TextCtrl(self, -1, '', size=(-1,75),style=wx.TE_MULTILINE)
  85. #
  86. # List Boxes
  87. #
  88. self.list_columns = wx.ListBox(self, -1, wx.DefaultPosition, (-1, -1), self.columns.keys(), wx.LB_MULTIPLE|wx.LB_SORT)
  89. self.list_values = wx.ListBox(self, -1, wx.DefaultPosition, (-1, -1), self.colvalues, wx.LB_MULTIPLE|wx.LB_SORT)
  90. #
  91. # Bindings
  92. #
  93. self.btn_uniqe.Bind(wx.EVT_BUTTON, self.GetUniqueValues)
  94. self.btn_uniqesample.Bind(wx.EVT_BUTTON, self.GetSampleValues)
  95. self.btn_is.Bind(wx.EVT_BUTTON, self.AddMark)
  96. self.btn_isnot.Bind(wx.EVT_BUTTON, self.AddMark)
  97. self.btn_like.Bind(wx.EVT_BUTTON, self.AddMark)
  98. self.btn_gt.Bind(wx.EVT_BUTTON, self.AddMark)
  99. self.btn_gtis.Bind(wx.EVT_BUTTON, self.AddMark)
  100. self.btn_or.Bind(wx.EVT_BUTTON, self.AddMark)
  101. self.btn_lt.Bind(wx.EVT_BUTTON, self.AddMark)
  102. self.btn_ltis.Bind(wx.EVT_BUTTON, self.AddMark)
  103. self.btn_not.Bind(wx.EVT_BUTTON, self.AddMark)
  104. self.btn_brackets.Bind(wx.EVT_BUTTON, self.AddMark)
  105. self.btn_prc.Bind(wx.EVT_BUTTON, self.AddMark)
  106. self.btn_and.Bind(wx.EVT_BUTTON, self.AddMark)
  107. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  108. self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
  109. self.btn_verify.Bind(wx.EVT_BUTTON, self.OnVerify)
  110. self.btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
  111. self.list_columns.Bind(wx.EVT_LISTBOX, self.AddColumnName)
  112. self.list_values.Bind(wx.EVT_LISTBOX, self.AddValue)
  113. self.__doLayout()
  114. def __doLayout(self):
  115. databasebox = wx.StaticBox(self, -1, "Database connection")
  116. databaseboxsizer = wx.StaticBoxSizer(databasebox,wx.VERTICAL)
  117. dbstr = "Database: %s\n" % (self.database)
  118. dbstr += "Driver: %s\n" % (self.driver)
  119. dbstr += "Table: %s" % (self.tablename)
  120. databaseboxsizer.Add(wx.StaticText(self,-1,dbstr), flag=wx.EXPAND)
  121. sqlbox = wx.StaticBox(self, -1, "%s" % self.heading)
  122. sqlboxsizer = wx.StaticBoxSizer(sqlbox,wx.VERTICAL)
  123. sqlboxsizer.Add(self.text_sql, flag=wx.EXPAND)
  124. pagesizer = wx.BoxSizer(wx.VERTICAL)
  125. buttonsizer1 = wx.GridBagSizer(2,2)
  126. buttonsizer1.Add(self.btn_clear, (0,0))
  127. buttonsizer1.Add(self.btn_verify, (0,1))
  128. #buttonsizer1.Add(self.btn_help, (0,2))
  129. #buttonsizer1.Add(self.btn_load, (0,2))
  130. # buttonsizer1.Add(self.btn_save, (0,3))
  131. buttonsizer1.Add(self.btn_apply, (0,2))
  132. buttonsizer2 = wx.GridBagSizer(2, 2)
  133. buttonsizer2.Add(self.btn_is, (0,0))
  134. buttonsizer2.Add(self.btn_isnot, (1,0))
  135. buttonsizer2.Add(self.btn_like, (2, 0))
  136. buttonsizer2.Add(self.btn_gt, (0, 1))
  137. buttonsizer2.Add(self.btn_gtis, (1, 1))
  138. buttonsizer2.Add(self.btn_or, (2, 1))
  139. buttonsizer2.Add(self.btn_lt, (0, 2))
  140. buttonsizer2.Add(self.btn_ltis, (1, 2))
  141. buttonsizer2.Add(self.btn_not, (2, 2))
  142. buttonsizer2.Add(self.btn_brackets, (0, 3))
  143. buttonsizer2.Add(self.btn_prc, (1, 3))
  144. buttonsizer2.Add(self.btn_and, (2, 3))
  145. buttonsizer3 = wx.GridSizer(4, 3, 3, 3)
  146. buttonsizer3.Add(self.btn_apply,0,wx.RIGHT,5)
  147. buttonsizer3.Add(self.btn_close,0,wx.RIGHT,5)
  148. buttonsizer4 = wx.BoxSizer(wx.HORIZONTAL)
  149. buttonsizer4.Add(self.btn_uniqesample,0,flag=wx.ALIGN_CENTER_HORIZONTAL,border=5)
  150. buttonsizer4.Add(self.btn_uniqe,0,flag=wx.ALIGN_CENTER_HORIZONTAL,border=5)
  151. hsizer1 = wx.BoxSizer(wx.HORIZONTAL)
  152. #hsizer2 = wx.BoxSizer(wx.HORIZONTAL)
  153. columnsbox = wx.StaticBox(self,-1,"Columns: ")
  154. valuesbox = wx.StaticBox(self,-1,"Values: ")
  155. #hsizer1.Add(wx.StaticText(self,-1, "Unique values: "), border=0, proportion=1)
  156. columnsizer = wx.StaticBoxSizer(columnsbox,wx.VERTICAL)
  157. valuesizer = wx.StaticBoxSizer(valuesbox,wx.VERTICAL)
  158. columnsizer.Add(self.list_columns, flag=wx.EXPAND,)
  159. valuesizer.Add(self.list_values, flag=wx.EXPAND)
  160. self.list_columns.SetMinSize((-1,130))
  161. self.list_values.SetMinSize((-1,100))
  162. valuesizer.Add(buttonsizer4)
  163. hsizer1.Add(columnsizer,border=0, proportion=1)
  164. hsizer1.Add(valuesizer,border=0, proportion=1)
  165. pagesizer.Add(databaseboxsizer,flag=wx.EXPAND,border=5)
  166. pagesizer.Add(hsizer1, 1,flag=wx.EXPAND,border=5)
  167. #pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5)
  168. #pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5)
  169. pagesizer.Add(buttonsizer2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, border=5)
  170. pagesizer.Add(sqlboxsizer, flag=wx.EXPAND,border=5)
  171. pagesizer.Add(buttonsizer1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, border=5)
  172. pagesizer.Add(buttonsizer3, proportion=0, flag=wx.TOP, border=5)
  173. self.SetAutoLayout(True)
  174. self.SetSizer(pagesizer)
  175. pagesizer.Fit(self)
  176. #pagesizer.SetSizeHints(self)
  177. self.Layout()
  178. self.Show(True)
  179. def GetColumns(self):
  180. """Get columns"""
  181. dbDescribe = gcmd.Command(['db.describe',
  182. '-c', '--q',
  183. 'table=%s' % self.tablename])
  184. # skip ncols and nrows lines
  185. for line in dbDescribe.ReadStdOutput()[2:]:
  186. num, name, ctype, length = line.strip().split(":")
  187. name.strip()
  188. #self.columns_names.append(name)
  189. self.columns[name] = {'type' : ctype}
  190. def GetUniqueValues(self,event,justsample=False):
  191. vals = []
  192. try:
  193. idx = self.list_columns.GetSelections()[0]
  194. except:
  195. return
  196. self.list_values.Clear()
  197. column = self.list_columns.GetString(idx)
  198. i = 0
  199. for line in os.popen("""db.select -c database=%s driver=%s sql="SELECT %s FROM %s" """ %\
  200. (self.database,self.driver,column,self.tablename)):
  201. if justsample and i < 256 or \
  202. not justsample:
  203. self.list_values.Insert(line.strip(),0)
  204. else:
  205. break
  206. i += 1
  207. def GetSampleValues(self,event):
  208. self.GetUniqueValues(None,True)
  209. def AddColumnName(self,event):
  210. idx = self.list_columns.GetSelections()[0]
  211. column = self.list_columns.GetString(idx)
  212. self.__addSomething(column)
  213. def AddValue(self,event):
  214. idx = self.list_values.GetSelections()[0]
  215. value = self.list_values.GetString(idx)
  216. idx = self.list_columns.GetSelections()[0]
  217. column = self.list_columns.GetString(idx)
  218. if self.columns[column]['type'].lower().find("chara") > -1:
  219. value = "'%s'" % value
  220. self.__addSomething(value)
  221. def AddMark(self,event):
  222. if event.GetId() == self.btn_is.GetId(): mark = "="
  223. elif event.GetId() == self.btn_isnot.GetId(): mark = "!="
  224. elif event.GetId() == self.btn_like.GetId(): mark = "LIKE"
  225. elif event.GetId() == self.btn_gt.GetId(): mark = ">"
  226. elif event.GetId() == self.btn_gtis.GetId(): mark = ">="
  227. elif event.GetId() == self.btn_lt.GetId(): mark = "<"
  228. elif event.GetId() == self.btn_ltis.GetId(): mark = "<="
  229. elif event.GetId() == self.btn_or.GetId(): mark = "OR"
  230. elif event.GetId() == self.btn_not.GetId(): mark = "NOT"
  231. elif event.GetId() == self.btn_and.GetId(): mark = "AND"
  232. elif event.GetId() == self.btn_brackets.GetId(): mark = "()"
  233. elif event.GetId() == self.btn_prc.GetId(): mark = "%"
  234. self.__addSomething(mark)
  235. def __addSomething(self,what):
  236. sqlstr = self.text_sql.GetValue()
  237. newsqlstr = ''
  238. position = self.text_sql.GetPosition()[0]
  239. selection = self.text_sql.GetSelection()
  240. newsqlstr = sqlstr[:position]
  241. try:
  242. if newsqlstr[-1] != " ":
  243. newsqlstr += " "
  244. except:
  245. pass
  246. newsqlstr += what
  247. newsqlstr += " "+sqlstr[position:]
  248. self.text_sql.SetValue(newsqlstr)
  249. self.text_sql.SetInsertionPoint(position)
  250. def OnApply(self,event):
  251. if self.parent:
  252. try:
  253. self.parent.text_query.SetValue= self.text_sql.GetValue().strip().replace("\n"," ")
  254. except:
  255. pass
  256. def OnVerify(self,event):
  257. if self.text_sql.GetValue():
  258. if os.system("""db.select -t driver=%s database=%s sql="SELECT * FROM %s WHERE %s" """ % \
  259. (self.driver, self.database,self.tablename,
  260. self.text_sql.GetValue().strip().replace("\n"," "))):
  261. # FIXME: LOG
  262. # print self.text_sql.GetValue().strip().replace("\n"," "), "not correct!"
  263. pass
  264. def OnClear(self, event):
  265. self.text_sql.SetValue("")
  266. def OnClose(self,event):
  267. self.Destroy()
  268. if __name__ == "__main__":
  269. if len(sys.argv) != 2:
  270. print >>sys.stderr, __doc__
  271. sys.exit()
  272. app = wx.App(0)
  273. sqlb = SQLFrame(None, -1, 'SQL Builder',sys.argv[1])
  274. app.MainLoop()