db.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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):
  134. """Return the name of vector connected to the table.
  135. It returns None if no vectors are connected to the table.
  136. >>> run_command('g.copy', vector='firestations,myfirestations')
  137. 0
  138. >>> db_table_in_vector('myfirestations')
  139. ['myfirestations@user1']
  140. >>> db_table_in_vector('mfirestations')
  141. >>> run_command('g.remove', flags='f', type='vector', name='myfirestations')
  142. 0
  143. :param str table: name of table to query
  144. """
  145. from .vector import vector_db
  146. nuldev = file(os.devnull, 'w')
  147. used = []
  148. vects = list_strings('vect')
  149. for vect in vects:
  150. for f in vector_db(vect, stderr=nuldev).values():
  151. if not f:
  152. continue
  153. if f['table'] == table:
  154. used.append(vect)
  155. break
  156. if len(used) > 0:
  157. return used
  158. else:
  159. return None
  160. def db_begin_transaction(driver):
  161. """Begin transaction.
  162. :return: SQL command as string
  163. """
  164. if driver in ('sqlite', 'pg'):
  165. return 'BEGIN'
  166. if driver == 'mysql':
  167. return 'START TRANSACTION'
  168. return ''
  169. def db_commit_transaction(driver):
  170. """Commit transaction.
  171. :return: SQL command as string
  172. """
  173. if driver in ('sqlite', 'pg', 'mysql'):
  174. return 'COMMIT'
  175. return ''