v.db.addtable.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env python3
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: v.db.addtable
  6. # AUTHOR(S): Markus Neteler
  7. # Converted to Python by Glynn Clements
  8. # Key column added by Martin Landa <landa.martin gmail.com>
  9. # Table index added by Markus Metz
  10. # PURPOSE: interface to db.execute to creates and add a new table to given vector map
  11. # COPYRIGHT: (C) 2005, 2007, 2008, 2011 by Markus Neteler & the GRASS Development Team
  12. #
  13. # This program is free software under the GNU General Public
  14. # License (>=v2). Read the file COPYING that comes with GRASS
  15. # for details.
  16. #
  17. #############################################################################
  18. # %module
  19. # % description: Creates and connects a new attribute table to a given layer of an existing vector map.
  20. # % keyword: vector
  21. # % keyword: attribute table
  22. # % keyword: database
  23. # %end
  24. # %option G_OPT_V_MAP
  25. # %end
  26. # %option
  27. # % key: table
  28. # % type: string
  29. # % description: Name of new attribute table (default: vector map name)
  30. # % required: no
  31. # % guisection: Definition
  32. # %end
  33. # %option
  34. # % key: layer
  35. # % type: integer
  36. # % description: Layer number where to add new attribute table
  37. # % answer: 1
  38. # % required: no
  39. # % guisection: Definition
  40. # %end
  41. # %option G_OPT_DB_KEYCOLUMN
  42. # % guisection: Definition
  43. # %end
  44. # %option
  45. # % key: columns
  46. # % type: string
  47. # % label: Name and type of the new column(s) ('name type [,name type, ...]')
  48. # % description: Types depend on database backend, but all support VARCHAR(), INT, DOUBLE PRECISION and DATE. Example: 'label varchar(250), value integer'
  49. # % required: no
  50. # % multiple: yes
  51. # % key_desc: name type
  52. # % guisection: Definition
  53. # %end
  54. import sys
  55. import os
  56. import grass.script as grass
  57. from grass.script.utils import decode
  58. from grass.exceptions import CalledModuleError
  59. def main():
  60. vector = options["map"]
  61. table = options["table"]
  62. layer = options["layer"]
  63. columns = options["columns"]
  64. key = options["key"]
  65. # does map exist in CURRENT mapset?
  66. mapset = grass.gisenv()["MAPSET"]
  67. if not grass.find_file(vector, element="vector", mapset=mapset)["file"]:
  68. grass.fatal(_("Vector map <%s> not found in current mapset") % vector)
  69. map_name = vector.split("@")[0]
  70. if not table:
  71. if layer == "1":
  72. grass.verbose(_("Using vector map name as table name: <%s>") % map_name)
  73. table = map_name
  74. else:
  75. # to avoid tables with identical names on higher layers
  76. table = "%s_%s" % (map_name, layer)
  77. grass.verbose(
  78. _("Using vector map name extended by layer number as table name: <%s>")
  79. % table
  80. )
  81. else:
  82. grass.verbose(_("Using user specified table name: %s") % table)
  83. # check if DB parameters are set, and if not set them.
  84. grass.run_command("db.connect", flags="c", quiet=True)
  85. grass.verbose(_("Creating new DB connection based on default mapset settings..."))
  86. kv = grass.db_connection()
  87. database = kv["database"]
  88. driver = kv["driver"]
  89. schema = kv["schema"]
  90. database2 = database.replace("$MAP/", map_name + "/")
  91. # maybe there is already a table linked to the selected layer?
  92. nuldev = open(os.devnull, "w")
  93. try:
  94. grass.vector_db(map_name, stderr=nuldev)[int(layer)]
  95. grass.fatal(_("There is already a table linked to layer <%s>") % layer)
  96. except KeyError:
  97. pass
  98. # maybe there is already a table with that name?
  99. tables = grass.read_command(
  100. "db.tables", flags="p", database=database2, driver=driver, stderr=nuldev
  101. )
  102. tables = decode(tables)
  103. if table not in tables.splitlines():
  104. colnames = []
  105. column_def = []
  106. if columns:
  107. column_def = []
  108. for x in " ".join(columns.split()).split(","):
  109. colname = x.lower().split()[0]
  110. if colname in colnames:
  111. grass.fatal(_("Duplicate column name '%s' not allowed") % colname)
  112. colnames.append(colname)
  113. column_def.append(x)
  114. # if not existing, create it:
  115. if key not in colnames:
  116. column_def.insert(0, "%s integer" % key)
  117. column_def = ",".join(column_def)
  118. grass.verbose(_("Creating table with columns (%s)...") % column_def)
  119. sql = "CREATE TABLE %s (%s)" % (table, column_def)
  120. try:
  121. grass.run_command("db.execute", database=database2, driver=driver, sql=sql)
  122. except CalledModuleError:
  123. grass.fatal(_("Unable to create table <%s>") % table)
  124. # connect the map to the DB:
  125. if schema:
  126. table = "{schema}.{table}".format(schema=schema, table=table)
  127. grass.verbose(_("Connecting new table to vector map <%s>...") % map_name)
  128. grass.run_command(
  129. "v.db.connect",
  130. quiet=True,
  131. map=map_name,
  132. database=database,
  133. driver=driver,
  134. layer=layer,
  135. table=table,
  136. key=key,
  137. )
  138. # finally we have to add cats into the attribute DB to make
  139. # modules such as v.what.rast happy: (creates new row for each
  140. # vector line):
  141. try:
  142. grass.run_command(
  143. "v.to.db",
  144. overwrite=True,
  145. map=map_name,
  146. layer=layer,
  147. option="cat",
  148. column=key,
  149. qlayer=layer,
  150. )
  151. except CalledModuleError:
  152. # remove link
  153. grass.run_command(
  154. "v.db.connect", quiet=True, flags="d", map=map_name, layer=layer
  155. )
  156. return 1
  157. grass.verbose(_("Current attribute table links:"))
  158. if grass.verbosity() > 2:
  159. grass.run_command("v.db.connect", flags="p", map=map_name)
  160. # write cmd history:
  161. grass.vector_history(map_name)
  162. return 0
  163. if __name__ == "__main__":
  164. options, flags = grass.parser()
  165. sys.exit(main())