tgis_core.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. """!@package grass.script.tgis_core
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS core functions to be used in Python tgis packages.
  4. This class provides the SQL interface for serialization and deserialization
  5. of map and space time dataset data.
  6. Usage:
  7. @code
  8. from grass.script import tgis_core as grass
  9. grass.create_temporal_database()
  10. ...
  11. @endcode
  12. (C) 2008-2011 by the GRASS Development Team
  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. @author Soeren Gebbert
  17. """
  18. import os
  19. import sqlite3
  20. import core
  21. from datetime import datetime, date, time
  22. def get_grass_location_db_path():
  23. grassenv = core.gisenv()
  24. dbpath = os.path.join(grassenv["GISDBASE"], grassenv["LOCATION_NAME"])
  25. return os.path.join(dbpath, "grass.db")
  26. def get_sql_template_path():
  27. base = os.getenv("GISBASE")
  28. base_etc = os.path.join(base, "etc")
  29. return os.path.join(base_etc, "sql")
  30. ###############################################################################
  31. def create_temporal_database():
  32. """This function creates the grass location database structure for raster, vector and raster3d maps
  33. as well as for the space-time datasets strds, str3ds and stvds"""
  34. database = get_grass_location_db_path()
  35. # Check if it already exists
  36. if os.path.exists(database):
  37. return False
  38. # Read all SQL scripts and templates
  39. map_tables_template_sql = open(os.path.join(get_sql_template_path(), "map_tables_template.sql"), 'r').read()
  40. raster_metadata_sql = open(os.path.join(get_sql_template_path(), "raster_metadata_table.sql"), 'r').read()
  41. raster3d_metadata_sql = open(os.path.join(get_sql_template_path(), "raster3d_metadata_table.sql"), 'r').read()
  42. vector_metadata_sql = open(os.path.join(get_sql_template_path(), "vector_metadata_table.sql"), 'r').read()
  43. stds_tables_template_sql = open(os.path.join(get_sql_template_path(), "stds_tables_template.sql"), 'r').read()
  44. strds_metadata_sql = open(os.path.join(get_sql_template_path(), "strds_metadata_table.sql"), 'r').read()
  45. str3ds_metadata_sql = open(os.path.join(get_sql_template_path(), "str3ds_metadata_table.sql"), 'r').read()
  46. stvds_metadata_sql = open(os.path.join(get_sql_template_path(), "stvds_metadata_table.sql"), 'r').read()
  47. # Create the raster, raster3d and vector tables
  48. raster_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "raster")
  49. vector_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "vector")
  50. raster3d_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "raster3d")
  51. # Create the space-time raster, raster3d and vector dataset tables
  52. strds_tables_sql = stds_tables_template_sql.replace("STDS", "strds")
  53. stvds_tables_sql = stds_tables_template_sql.replace("STDS", "stvds")
  54. str3ds_tables_sql = stds_tables_template_sql.replace("STDS", "str3ds")
  55. # Check for completion
  56. sqlite3.complete_statement(raster_tables_sql)
  57. sqlite3.complete_statement(vector_tables_sql)
  58. sqlite3.complete_statement(raster3d_tables_sql)
  59. sqlite3.complete_statement(raster_metadata_sql)
  60. sqlite3.complete_statement(vector_metadata_sql)
  61. sqlite3.complete_statement(raster3d_metadata_sql)
  62. sqlite3.complete_statement(strds_tables_sql)
  63. sqlite3.complete_statement(stvds_tables_sql)
  64. sqlite3.complete_statement(str3ds_tables_sql)
  65. sqlite3.complete_statement(strds_metadata_sql)
  66. sqlite3.complete_statement(stvds_metadata_sql)
  67. sqlite3.complete_statement(str3ds_metadata_sql)
  68. # Connect to database
  69. connection = sqlite3.connect(database)
  70. cursor = connection.cursor()
  71. # Execute the SQL statements
  72. # Create the global tables for the native grass datatypes
  73. cursor.executescript(raster_tables_sql)
  74. cursor.executescript(raster_metadata_sql)
  75. cursor.executescript(vector_tables_sql)
  76. cursor.executescript(vector_metadata_sql)
  77. cursor.executescript(raster3d_tables_sql)
  78. cursor.executescript(raster3d_metadata_sql)
  79. # Create the tables for the new space-time datatypes
  80. cursor.executescript(strds_tables_sql)
  81. cursor.executescript(strds_metadata_sql)
  82. cursor.executescript(stvds_tables_sql)
  83. cursor.executescript(stvds_metadata_sql)
  84. cursor.executescript(str3ds_tables_sql)
  85. cursor.executescript(str3ds_metadata_sql)
  86. connection.commit()
  87. cursor.close()
  88. ###############################################################################
  89. class dict_sql_serializer(object):
  90. def __init__(self):
  91. self.D = {}
  92. def serialize(self, type, table, where=None):
  93. """Convert the internal dictionary into a string of semicolon separated SQL statements
  94. The keys are the colum names and the values are the row entries
  95. @type must be SELECT. INSERT, UPDATE
  96. @table The name of the table to select, insert or update
  97. @where The optinal where statment
  98. @return the sql string
  99. """
  100. sql = ""
  101. args = []
  102. # Create ordered select statement
  103. if type == "SELECT":
  104. sql += 'SELECT '
  105. count = 0
  106. for key in self.D.keys():
  107. if count == 0:
  108. sql += ' %s ' % key
  109. else:
  110. sql += ' , %s ' % key
  111. count += 1
  112. sql += ' FROM ' + table + ' '
  113. if where:
  114. sql += where
  115. # Create insert statement
  116. if type =="INSERT":
  117. count = 0
  118. sql += 'INSERT INTO ' + table + ' ('
  119. for key in self.D.keys():
  120. if count == 0:
  121. sql += ' %s ' % key
  122. else:
  123. sql += ' ,%s ' % key
  124. count += 1
  125. count = 0
  126. sql += ') VALUES ('
  127. for key in self.D.keys():
  128. if count == 0:
  129. sql += '?'
  130. else:
  131. sql += ',?'
  132. count += 1
  133. args.append(self.D[key])
  134. sql += ') '
  135. if where:
  136. sql += where
  137. # Create update statement
  138. if type =="UPDATE":
  139. count = 0
  140. sql += 'UPDATE ' + table + ' SET '
  141. for key in self.D.keys():
  142. # Update only entries which are not None
  143. if self.D[key] != None:
  144. if count == 0:
  145. sql += ' %s = ? ' % key
  146. else:
  147. sql += ' ,%s = ? ' % key
  148. count += 1
  149. args.append(self.D[key])
  150. if where:
  151. sql += where
  152. return sql, tuple(args)
  153. def deserialize(self, row):
  154. """Convert the content of the sqlite row into the internal dictionary"""
  155. self.D = {}
  156. for key in row.keys():
  157. self.D[key] = row[key]
  158. def clear(self):
  159. """Remove all the content of this class"""
  160. self.D = {}
  161. def print_self(self):
  162. print self.D
  163. def test(self):
  164. t = dict_sql_serializer()
  165. t.D["id"] = "soil@PERMANENT"
  166. t.D["name"] = "soil"
  167. t.D["mapset"] = "PERMANENT"
  168. t.D["creator"] = "soeren"
  169. t.D["creation_time"] = datetime.now()
  170. t.D["modification_time"] = datetime.now()
  171. t.D["revision"] = 1
  172. sql, values = t.serialize(type="SELECT", table="raster_base")
  173. print sql, '\n', values
  174. sql, values = t.serialize(type="INSERT", table="raster_base")
  175. print sql, '\n', values
  176. sql, values = t.serialize(type="UPDATE", table="raster_base")
  177. print sql, '\n', values
  178. ###############################################################################
  179. class sql_database_interface(dict_sql_serializer):
  180. """This is the sql database interface to sqlite3"""
  181. def __init__(self, table=None, ident=None, database=None):
  182. dict_sql_serializer.__init__(self)
  183. self.table = table # Name of the table, set in the subclass
  184. if database == None:
  185. self.database = get_grass_location_db_path()
  186. else:
  187. self.database = database
  188. self.ident = ident
  189. def get_table_name(self):
  190. return self.table
  191. def connect(self):
  192. self.connection = sqlite3.connect(self.database, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
  193. self.connection.row_factory = sqlite3.Row
  194. self.cursor = self.connection.cursor()
  195. def close(self):
  196. self.connection.commit()
  197. self.cursor.close()
  198. def get_delete_statement(self):
  199. return "DELETE FROM " + self.get_table_name() + " WHERE id = \"" + str(self.ident) + "\""
  200. def delete(self):
  201. self.connect()
  202. sql = self.get_delete_statement()
  203. #print sql
  204. self.cursor.execute(sql)
  205. self.close()
  206. def get_is_in_db_statement(self):
  207. return "SELECT id FROM " + self.get_table_name() + " WHERE id = \"" + str(self.ident) + "\""
  208. def is_in_db(self):
  209. self.connect()
  210. sql = self.get_is_in_db_statement()
  211. #print sql
  212. self.cursor.execute(sql)
  213. row = self.cursor.fetchone()
  214. self.close()
  215. # Nothing found
  216. if row == None:
  217. return False
  218. return True
  219. def get_select_statement(self):
  220. return self.serialize("SELECT", self.get_table_name(), "WHERE id = \"" + str(self.ident) + "\"")
  221. def select(self):
  222. self.connect()
  223. sql, args = self.get_select_statement()
  224. #print sql
  225. #print args
  226. if len(args) == 0:
  227. self.cursor.execute(sql)
  228. else:
  229. self.cursor.execute(sql, args)
  230. row = self.cursor.fetchone()
  231. # Nothing found
  232. if row == None:
  233. return False
  234. if len(row) > 0:
  235. self.deserialize(row)
  236. else:
  237. raise IOError
  238. self.close()
  239. return True
  240. def get_insert_statement(self):
  241. return self.serialize("INSERT", self.get_table_name())
  242. def insert(self):
  243. self.connect()
  244. sql, args = self.get_insert_statement()
  245. #print sql
  246. #print args
  247. self.cursor.execute(sql, args)
  248. self.close()
  249. def get_update_statement(self):
  250. return self.serialize("UPDATE", self.get_table_name(), "WHERE id = \"" + str(self.ident) + "\"")
  251. def update(self):
  252. if self.ident == None:
  253. raise IOError("Missing identifer");
  254. sql, args = self.get_update_statement()
  255. #print sql
  256. #print args
  257. self.connect()
  258. self.cursor.execute(sql, args)
  259. self.close()