sqlbuilder.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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.ETCDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
  33. #
  34. # variables
  35. #
  36. self.vectmap = vectmap
  37. print self.vectmap
  38. if not "@" in self.vectmap:
  39. self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable ("MAPSET")
  40. self.mapname, self.mapset = self.vectmap.split("@")
  41. self.layer,self.tablename, self.column, self.database, self.driver =\
  42. os.popen("v.db.connect -g map=%s" %\
  43. (self.vectmap)).readlines()[0].strip().split()
  44. self.qtype = qtype # type of the uqery: SELECT, UPDATE, DELETE, ...
  45. self.column_names = [] # array with column names
  46. self.columns = {} # array with colum properties
  47. self.colvalues = [] # arrya with uniqe values in selected column
  48. self.heading = ""
  49. self.parent = parent
  50. if self.qtype.lower()=="select":
  51. self.heading = "SELECT * FROM %s WHERE" % self.tablename
  52. # Init
  53. self.GetColumns()
  54. #
  55. # Buttons
  56. #
  57. self.btn_clear = wx.Button(self, -1, "Clear")
  58. self.btn_verify = wx.Button(self, -1, "Verify")
  59. #self.btn_help = wx.Button(self, -1, "Help")
  60. # self.btn_load = wx.Button(self, -1, "Load")
  61. # self.btn_save = wx.Button(self, -1, "Save")
  62. self.btn_apply = wx.Button(self, -1, "Apply")
  63. self.btn_close = wx.Button(self, -1, "Close")
  64. self.btn_uniqe = wx.Button(self, -1, "Get all values")
  65. self.btn_uniqesample = wx.Button(self, -1, "Get sample")
  66. self.btn_is = wx.Button(self, -1, "=")
  67. self.btn_isnot = wx.Button(self, -1, "!=")
  68. self.btn_like = wx.Button(self, -1, "LIKE")
  69. self.btn_gt = wx.Button(self, -1, ">=")
  70. self.btn_gtis = wx.Button(self, -1, ">")
  71. self.btn_lt = wx.Button(self, -1, "<=")
  72. self.btn_ltis = wx.Button(self, -1, "<")
  73. self.btn_or = wx.Button(self, -1, "OR")
  74. self.btn_not = wx.Button(self, -1, "NOT")
  75. self.btn_and = wx.Button(self, -1, "AND")
  76. self.btn_brackets = wx.Button(self, -1, "()")
  77. self.btn_prc = wx.Button(self, -1, "%")
  78. #
  79. # Text labels
  80. #
  81. #self.label_headding = wx.StaticText(self, -1, '')
  82. #
  83. # Textareas
  84. #
  85. self.text_sql = wx.TextCtrl(self, -1, '', size=(-1,75),style=wx.TE_MULTILINE)
  86. #
  87. # List Boxes
  88. #
  89. self.list_columns = wx.ListBox(self, -1, wx.DefaultPosition, (-1, -1), self.column_names, wx.LB_MULTIPLE|wx.LB_SORT)
  90. self.list_values = wx.ListBox(self, -1, wx.DefaultPosition, (-1, -1), self.colvalues, wx.LB_MULTIPLE|wx.LB_SORT)
  91. #
  92. # Bindings
  93. #
  94. self.btn_uniqe.Bind(wx.EVT_BUTTON, self.GetUniqueValues)
  95. self.btn_uniqesample.Bind(wx.EVT_BUTTON, self.GetSampleValues)
  96. self.btn_is.Bind(wx.EVT_BUTTON, self.AddMark)
  97. self.btn_isnot.Bind(wx.EVT_BUTTON, self.AddMark)
  98. self.btn_like.Bind(wx.EVT_BUTTON, self.AddMark)
  99. self.btn_gt.Bind(wx.EVT_BUTTON, self.AddMark)
  100. self.btn_gtis.Bind(wx.EVT_BUTTON, self.AddMark)
  101. self.btn_or.Bind(wx.EVT_BUTTON, self.AddMark)
  102. self.btn_lt.Bind(wx.EVT_BUTTON, self.AddMark)
  103. self.btn_ltis.Bind(wx.EVT_BUTTON, self.AddMark)
  104. self.btn_not.Bind(wx.EVT_BUTTON, self.AddMark)
  105. self.btn_brackets.Bind(wx.EVT_BUTTON, self.AddMark)
  106. self.btn_prc.Bind(wx.EVT_BUTTON, self.AddMark)
  107. self.btn_and.Bind(wx.EVT_BUTTON, self.AddMark)
  108. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  109. self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
  110. self.btn_verify.Bind(wx.EVT_BUTTON, self.OnVerify)
  111. self.btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
  112. self.list_columns.Bind(wx.EVT_LISTBOX, self.AddColumnName)
  113. self.list_values.Bind(wx.EVT_LISTBOX, self.AddValue)
  114. self.__doLayout()
  115. def __doLayout(self):
  116. databasebox = wx.StaticBox(self, -1, "Database connection")
  117. databaseboxsizer = wx.StaticBoxSizer(databasebox,wx.VERTICAL)
  118. dbstr = "Database: %s\n" % (self.database)
  119. dbstr += "Driver: %s\n" % (self.driver)
  120. dbstr += "Table: %s" % (self.tablename)
  121. databaseboxsizer.Add(wx.StaticText(self,-1,dbstr), flag=wx.EXPAND)
  122. sqlbox = wx.StaticBox(self, -1, "%s" % self.heading)
  123. sqlboxsizer = wx.StaticBoxSizer(sqlbox,wx.VERTICAL)
  124. sqlboxsizer.Add(self.text_sql, flag=wx.EXPAND)
  125. pagesizer = wx.BoxSizer(wx.VERTICAL)
  126. buttonsizer1 = wx.GridBagSizer(2,2)
  127. buttonsizer1.Add(self.btn_clear, (0,0))
  128. buttonsizer1.Add(self.btn_verify, (0,1))
  129. #buttonsizer1.Add(self.btn_help, (0,2))
  130. #buttonsizer1.Add(self.btn_load, (0,2))
  131. # buttonsizer1.Add(self.btn_save, (0,3))
  132. buttonsizer1.Add(self.btn_apply, (0,2))
  133. buttonsizer2 = wx.GridBagSizer(2, 2)
  134. buttonsizer2.Add(self.btn_is, (0,0))
  135. buttonsizer2.Add(self.btn_isnot, (1,0))
  136. buttonsizer2.Add(self.btn_like, (2, 0))
  137. buttonsizer2.Add(self.btn_gt, (0, 1))
  138. buttonsizer2.Add(self.btn_gtis, (1, 1))
  139. buttonsizer2.Add(self.btn_or, (2, 1))
  140. buttonsizer2.Add(self.btn_lt, (0, 2))
  141. buttonsizer2.Add(self.btn_ltis, (1, 2))
  142. buttonsizer2.Add(self.btn_not, (2, 2))
  143. buttonsizer2.Add(self.btn_brackets, (0, 3))
  144. buttonsizer2.Add(self.btn_prc, (1, 3))
  145. buttonsizer2.Add(self.btn_and, (2, 3))
  146. buttonsizer3 = wx.GridSizer(4, 3, 3, 3)
  147. buttonsizer3.Add(self.btn_apply,0,wx.RIGHT,5)
  148. buttonsizer3.Add(self.btn_close,0,wx.RIGHT,5)
  149. buttonsizer4 = wx.BoxSizer(wx.HORIZONTAL)
  150. buttonsizer4.Add(self.btn_uniqesample,0,flag=wx.ALIGN_CENTER_HORIZONTAL,border=5)
  151. buttonsizer4.Add(self.btn_uniqe,0,flag=wx.ALIGN_CENTER_HORIZONTAL,border=5)
  152. hsizer1 = wx.BoxSizer(wx.HORIZONTAL)
  153. #hsizer2 = wx.BoxSizer(wx.HORIZONTAL)
  154. columnsbox = wx.StaticBox(self,-1,"Columns: ")
  155. valuesbox = wx.StaticBox(self,-1,"Values: ")
  156. #hsizer1.Add(wx.StaticText(self,-1, "Unique values: "), border=0, proportion=1)
  157. columnsizer = wx.StaticBoxSizer(columnsbox,wx.VERTICAL)
  158. valuesizer = wx.StaticBoxSizer(valuesbox,wx.VERTICAL)
  159. columnsizer.Add(self.list_columns, flag=wx.EXPAND,)
  160. valuesizer.Add(self.list_values, flag=wx.EXPAND)
  161. self.list_columns.SetMinSize((-1,130))
  162. self.list_values.SetMinSize((-1,100))
  163. valuesizer.Add(buttonsizer4)
  164. hsizer1.Add(columnsizer,border=0, proportion=1)
  165. hsizer1.Add(valuesizer,border=0, proportion=1)
  166. pagesizer.Add(databaseboxsizer,flag=wx.EXPAND,border=5)
  167. pagesizer.Add(hsizer1, 1,flag=wx.EXPAND,border=5)
  168. #pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5)
  169. #pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5)
  170. pagesizer.Add(buttonsizer2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, border=5)
  171. pagesizer.Add(sqlboxsizer, flag=wx.EXPAND,border=5)
  172. pagesizer.Add(buttonsizer1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, border=5)
  173. pagesizer.Add(buttonsizer3, proportion=0, flag=wx.TOP, border=5)
  174. self.SetAutoLayout(True)
  175. self.SetSizer(pagesizer)
  176. pagesizer.Fit(self)
  177. #pagesizer.SetSizeHints(self)
  178. self.Layout()
  179. self.Show(True)
  180. def GetColumns(self):
  181. """Get columns"""
  182. dbDescribe = gcmd.Command(['db.describe',
  183. '-c', '--q',
  184. 'table=%s' % self.tablename])
  185. # skip ncols and nrows lines
  186. for line in dbDescribe.ReadStdOutput()[2:]:
  187. num, name, ctype, length = line.strip().split(":")
  188. name.strip()
  189. #self.columns_names.append(name)
  190. self.columns[name] = {'type' : ctype}
  191. def GetUniqueValues(self,event,justsample=False):
  192. vals = []
  193. try:
  194. idx = self.list_columns.GetSelections()[0]
  195. except:
  196. return
  197. self.list_values.Clear()
  198. column = self.list_columns.GetString(idx)
  199. i = 0
  200. for line in os.popen("""db.select -c database=%s driver=%s sql="SELECT %s FROM %s" """ %\
  201. (self.database,self.driver,column,self.tablename)):
  202. if justsample and i < 256 or \
  203. not justsample:
  204. self.list_values.Insert(line.strip(),0)
  205. else:
  206. break
  207. i += 1
  208. def GetSampleValues(self,event):
  209. self.GetUniqueValues(None,True)
  210. def AddColumnName(self,event):
  211. idx = self.list_columns.GetSelections()[0]
  212. column = self.list_columns.GetString(idx)
  213. self.__addSomething(column)
  214. def AddValue(self,event):
  215. idx = self.list_values.GetSelections()[0]
  216. value = self.list_values.GetString(idx)
  217. idx = self.list_columns.GetSelections()[0]
  218. column = self.list_columns.GetString(idx)
  219. if self.columns[column]['type'].lower().find("chara") > -1:
  220. value = "'%s'" % value
  221. self.__addSomething(value)
  222. def AddMark(self,event):
  223. if event.GetId() == self.btn_is.GetId(): mark = "="
  224. elif event.GetId() == self.btn_isnot.GetId(): mark = "!="
  225. elif event.GetId() == self.btn_like.GetId(): mark = "LIKE"
  226. elif event.GetId() == self.btn_gt.GetId(): mark = ">"
  227. elif event.GetId() == self.btn_gtis.GetId(): mark = ">="
  228. elif event.GetId() == self.btn_lt.GetId(): mark = "<"
  229. elif event.GetId() == self.btn_ltis.GetId(): mark = "<="
  230. elif event.GetId() == self.btn_or.GetId(): mark = "OR"
  231. elif event.GetId() == self.btn_not.GetId(): mark = "NOT"
  232. elif event.GetId() == self.btn_and.GetId(): mark = "AND"
  233. elif event.GetId() == self.btn_brackets.GetId(): mark = "()"
  234. elif event.GetId() == self.btn_prc.GetId(): mark = "%"
  235. self.__addSomething(mark)
  236. def __addSomething(self,what):
  237. sqlstr = self.text_sql.GetValue()
  238. newsqlstr = ''
  239. position = self.text_sql.GetPosition()[0]
  240. selection = self.text_sql.GetSelection()
  241. newsqlstr = sqlstr[:position]
  242. try:
  243. if newsqlstr[-1] != " ":
  244. newsqlstr += " "
  245. except:
  246. pass
  247. newsqlstr += what
  248. newsqlstr += " "+sqlstr[position:]
  249. self.text_sql.SetValue(newsqlstr)
  250. self.text_sql.SetInsertionPoint(position)
  251. def OnApply(self,event):
  252. if self.parent:
  253. try:
  254. self.parent.text_query.SetValue= self.text_sql.GetValue().strip().replace("\n"," ")
  255. except:
  256. pass
  257. def OnVerify(self,event):
  258. if self.text_sql.GetValue():
  259. if os.system("""db.select -t driver=%s database=%s sql="SELECT * FROM %s WHERE %s" """ % \
  260. (self.driver, self.database,self.tablename,
  261. self.text_sql.GetValue().strip().replace("\n"," "))):
  262. # FIXME: LOG
  263. print self.text_sql.GetValue().strip().replace("\n"," "), "not correct!"
  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()