db.py 6.3 KB

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