db.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. """
  2. Database related functions to be used in Python scripts.
  3. Usage:
  4. ::
  5. from grass.script import db as grass
  6. grass.db_describe(table)
  7. ...
  8. (C) 2008-2015 by the GRASS Development Team
  9. This program is free software under the GNU General Public
  10. License (>=v2). Read the file COPYING that comes with GRASS
  11. for details.
  12. .. sectionauthor:: Glynn Clements
  13. .. sectionauthor:: Martin Landa <landa.martin gmail.com>
  14. """
  15. from __future__ import absolute_import
  16. from .core import *
  17. from .utils import try_remove
  18. from grass.exceptions import CalledModuleError
  19. def db_describe(table, **args):
  20. """Return the list of columns for a database table
  21. (interface to `db.describe -c`). Example:
  22. >>> run_command('g.copy', vector='firestations,myfirestations')
  23. 0
  24. >>> db_describe('myfirestations') # doctest: +ELLIPSIS
  25. {'nrows': 71, 'cols': [['cat', 'INTEGER', '20'], ... 'ncols': 22}
  26. >>> run_command('g.remove', flags='f', type='vector', name='myfirestations')
  27. 0
  28. :param str table: table name
  29. :param list args:
  30. :return: parsed module output
  31. """
  32. s = read_command('db.describe', flags='c', table=table, **args)
  33. if not s:
  34. fatal(_("Unable to describe table <%s>") % table)
  35. cols = []
  36. result = {}
  37. for l in s.splitlines():
  38. f = l.split(':')
  39. key = f[0]
  40. f[1] = f[1].lstrip(' ')
  41. if key.startswith('Column '):
  42. n = int(key.split(' ')[1])
  43. cols.insert(n, f[1:])
  44. elif key in ['ncols', 'nrows']:
  45. result[key] = int(f[1])
  46. else:
  47. result[key] = f[1:]
  48. result['cols'] = cols
  49. return result
  50. def db_table_exist(table, **args):
  51. """Check if table exists.
  52. If no driver or database are given, then default settings is used
  53. (check db_connection()).
  54. >>> run_command('g.copy', vector='firestations,myfirestations')
  55. 0
  56. >>> db_table_exist('myfirestations')
  57. True
  58. >>> run_command('g.remove', flags='f', type='vector', name='myfirestations')
  59. 0
  60. :param str table: table name
  61. :param args:
  62. :return: True for success, False otherwise
  63. """
  64. nuldev = file(os.devnull, 'w+')
  65. ok = True
  66. try:
  67. run_command('db.describe', flags='c', table=table,
  68. stdout=nuldev, stderr=nuldev, **args)
  69. except CalledModuleError:
  70. ok = False
  71. finally:
  72. nuldev.close()
  73. return ok
  74. def db_connection(force=False):
  75. """Return the current database connection parameters
  76. (interface to `db.connect -g`). Example:
  77. >>> db_connection()
  78. {'group': '', 'schema': '', 'driver': 'sqlite', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db'}
  79. :param force True to set up default DB connection if not defined
  80. :return: parsed output of db.connect
  81. """
  82. try:
  83. nuldev = file(os.devnull, 'w')
  84. conn = parse_command('db.connect', flags='g', stderr=nuldev)
  85. nuldev.close()
  86. except CalledModuleError:
  87. conn = None
  88. if not conn and force:
  89. run_command('db.connect', flags='c')
  90. conn = parse_command('db.connect', flags='g')
  91. return conn
  92. def db_select(sql=None, filename=None, table=None, **args):
  93. """Perform SQL select statement
  94. Note: one of <em>sql</em>, <em>filename</em>, or <em>table</em>
  95. arguments must be provided.
  96. Examples:
  97. >>> run_command('g.copy', vector='firestations,myfirestations')
  98. 0
  99. >>> db_select(sql = 'SELECT cat,CITY FROM myfirestations WHERE cat < 4')
  100. (('1', 'Morrisville'), ('2', 'Morrisville'), ('3', 'Apex'))
  101. Simplyfied usage (it performs <tt>SELECT * FROM myfirestations</tt>.)
  102. >>> db_select(table = 'myfirestations') # doctest: +ELLIPSIS
  103. (('1', '24', 'Morrisville #3', ... 'HS2A', '1.37'))
  104. >>> run_command('g.remove', flags='f', type='vector', name='myfirestations')
  105. 0
  106. :param str sql: SQL statement to perform (or None)
  107. :param str filename: name of file with SQL statements (or None)
  108. :param str table: name of table to query (or None)
  109. :param str args: see \gmod{db.select} arguments
  110. """
  111. fname = tempfile(create=False)
  112. if sql:
  113. args['sql'] = sql
  114. elif filename:
  115. args['input'] = filename
  116. elif table:
  117. args['table'] = table
  118. else:
  119. fatal(_("Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be provided") %
  120. {'sql': 'sql', 'filename': 'filename', 'table': 'table'} )
  121. if 'sep' not in args:
  122. args['sep'] = '|'
  123. try:
  124. run_command('db.select', quiet=True, flags='c',
  125. output=fname, **args)
  126. except CalledModuleError:
  127. fatal(_("Fetching data failed"))
  128. ofile = open(fname)
  129. result = [tuple(x.rstrip(os.linesep).split(args['sep'])) for x in ofile.readlines()]
  130. ofile.close()
  131. try_remove(fname)
  132. return tuple(result)
  133. def db_table_in_vector(table, mapset='.'):
  134. """Return the name of vector connected to the table.
  135. By default it check only in the current mapset, because the same table
  136. name could be used also in other mapset by other vector.
  137. It returns None if no vectors are connected to the table.
  138. >>> run_command('g.copy', vector='firestations,myfirestations')
  139. 0
  140. >>> db_table_in_vector('myfirestations')
  141. ['myfirestations@user1']
  142. >>> db_table_in_vector('mfirestations')
  143. >>> run_command('g.remove', flags='f', type='vector', name='myfirestations')
  144. 0
  145. :param str table: name of table to query
  146. """
  147. from .vector import vector_db
  148. nuldev = file(os.devnull, 'w')
  149. used = []
  150. vects = list_strings('vector', mapset=mapset)
  151. for vect in vects:
  152. for f in vector_db(vect, stderr=nuldev).values():
  153. if not f:
  154. continue
  155. if f['table'] == table:
  156. used.append(vect)
  157. break
  158. if len(used) > 0:
  159. return used
  160. else:
  161. return None
  162. def db_begin_transaction(driver):
  163. """Begin transaction.
  164. :return: SQL command as string
  165. """
  166. if driver in ('sqlite', 'pg'):
  167. return 'BEGIN'
  168. if driver == 'mysql':
  169. return 'START TRANSACTION'
  170. return ''
  171. def db_commit_transaction(driver):
  172. """Commit transaction.
  173. :return: SQL command as string
  174. """
  175. if driver in ('sqlite', 'pg', 'mysql'):
  176. return 'COMMIT'
  177. return ''