sqlbuilder.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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 grass
  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 + "@" + grass.gisenv()['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. ret = gcmd.RunCommand('db.describe',
  182. quiet = True,
  183. read = True,
  184. flags = 'c',
  185. table = self.tablename)
  186. # skip ncols and nrows lines
  187. for line in ret.splitlines():
  188. num, name, ctype, length = line.strip().split(":")
  189. name.strip()
  190. #self.columns_names.append(name)
  191. self.columns[name] = {'type' : ctype}
  192. def GetUniqueValues(self,event,justsample=False):
  193. vals = []
  194. try:
  195. idx = self.list_columns.GetSelections()[0]
  196. except:
  197. return
  198. self.list_values.Clear()
  199. column = self.list_columns.GetString(idx)
  200. i = 0
  201. for line in os.popen("""db.select -c database=%s driver=%s sql="SELECT %s FROM %s" """ %\
  202. (self.database,self.driver,column,self.tablename)):
  203. if justsample and i < 256 or \
  204. not justsample:
  205. self.list_values.Insert(line.strip(),0)
  206. else:
  207. break
  208. i += 1
  209. def GetSampleValues(self,event):
  210. self.GetUniqueValues(None,True)
  211. def AddColumnName(self,event):
  212. idx = self.list_columns.GetSelections()[0]
  213. column = self.list_columns.GetString(idx)
  214. self.__addSomething(column)
  215. def AddValue(self,event):
  216. idx = self.list_values.GetSelections()[0]
  217. value = self.list_values.GetString(idx)
  218. idx = self.list_columns.GetSelections()[0]
  219. column = self.list_columns.GetString(idx)
  220. if self.columns[column]['type'].lower().find("chara") > -1:
  221. value = "'%s'" % value
  222. self.__addSomething(value)
  223. def AddMark(self,event):
  224. if event.GetId() == self.btn_is.GetId(): mark = "="
  225. elif event.GetId() == self.btn_isnot.GetId(): mark = "!="
  226. elif event.GetId() == self.btn_like.GetId(): mark = "LIKE"
  227. elif event.GetId() == self.btn_gt.GetId(): mark = ">"
  228. elif event.GetId() == self.btn_gtis.GetId(): mark = ">="
  229. elif event.GetId() == self.btn_lt.GetId(): mark = "<"
  230. elif event.GetId() == self.btn_ltis.GetId(): mark = "<="
  231. elif event.GetId() == self.btn_or.GetId(): mark = "OR"
  232. elif event.GetId() == self.btn_not.GetId(): mark = "NOT"
  233. elif event.GetId() == self.btn_and.GetId(): mark = "AND"
  234. elif event.GetId() == self.btn_brackets.GetId(): mark = "()"
  235. elif event.GetId() == self.btn_prc.GetId(): mark = "%"
  236. self.__addSomething(mark)
  237. def __addSomething(self,what):
  238. sqlstr = self.text_sql.GetValue()
  239. newsqlstr = ''
  240. position = self.text_sql.GetPosition()[0]
  241. selection = self.text_sql.GetSelection()
  242. newsqlstr = sqlstr[:position]
  243. try:
  244. if newsqlstr[-1] != " ":
  245. newsqlstr += " "
  246. except:
  247. pass
  248. newsqlstr += what
  249. newsqlstr += " "+sqlstr[position:]
  250. self.text_sql.SetValue(newsqlstr)
  251. self.text_sql.SetInsertionPoint(position)
  252. def OnApply(self,event):
  253. if self.parent:
  254. try:
  255. self.parent.text_query.SetValue= self.text_sql.GetValue().strip().replace("\n"," ")
  256. except:
  257. pass
  258. def OnVerify(self,event):
  259. if self.text_sql.GetValue():
  260. if os.system("""db.select -t driver=%s database=%s sql="SELECT * FROM %s WHERE %s" """ % \
  261. (self.driver, self.database,self.tablename,
  262. self.text_sql.GetValue().strip().replace("\n"," "))):
  263. # FIXME: LOG
  264. # print self.text_sql.GetValue().strip().replace("\n"," "), "not correct!"
  265. pass
  266. def OnClear(self, event):
  267. self.text_sql.SetValue("")
  268. def OnClose(self,event):
  269. self.Destroy()
  270. if __name__ == "__main__":
  271. if len(sys.argv) != 2:
  272. print >>sys.stderr, __doc__
  273. sys.exit()
  274. app = wx.App(0)
  275. sqlb = SQLFrame(None, -1, 'SQL Builder',sys.argv[1])
  276. app.MainLoop()