abstract_space_time_dataset.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in temporal GIS Python library package.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. ...
  8. @endcode
  9. (C) 2008-2011 by the GRASS Development Team
  10. This program is free software under the GNU General Public
  11. License (>=v2). Read the file COPYING that comes with GRASS
  12. for details.
  13. @author Soeren Gebbert
  14. """
  15. from abstract_dataset import *
  16. ###############################################################################
  17. class abstract_space_time_dataset(abstract_dataset):
  18. """Abstract space time dataset class
  19. This class represents a space time dataset. Convenient functions
  20. to select, update, insert or delete objects of this type in the SQL
  21. temporal database exists as well as functions to register or unregister
  22. raster maps.
  23. Parts of the temporal logic are implemented in the SQL temporal database,
  24. like the computation of the temporal and spatial extent as well as the
  25. collecting of metadata.
  26. """
  27. def __init__(self, ident):
  28. self.reset(ident)
  29. def get_new_instance(self, ident=None):
  30. """Return a new instance with the type of this class
  31. @param ident: The unique identifier of the new object
  32. """
  33. raise IOError("This method must be implemented in the subclasses")
  34. def get_new_map_instance(self, ident=None):
  35. """Return a new instance of a map dataset which is associated with the type of this class
  36. @param ident: The unique identifier of the new object
  37. """
  38. raise IOError("This method must be implemented in the subclasses")
  39. def get_map_register(self):
  40. """Return the name of the map register table"""
  41. raise IOError("This method must be implemented in the subclasses")
  42. def set_map_register(self, name):
  43. """Set the name of the map register table
  44. This table stores all map names which are registered in this space time dataset.
  45. @param name: The name of the register table
  46. """
  47. raise IOError("This method must be implemented in the subclasses")
  48. def set_initial_values(self, granularity, temporal_type, semantic_type, \
  49. title=None, description=None):
  50. """Set the initial values of the space time dataset
  51. @param granularity: The temporal granularity of this dataset. This value
  52. should be computed by the space time dataset itself,
  53. based on the granularity of the registered maps
  54. @param temporal_type: The temporal type of this space time dataset (absolute or relative)
  55. @param semantic_type: The semantic type of this dataset
  56. @param title: The title
  57. @param description: The description of this dataset
  58. """
  59. if temporal_type == "absolute":
  60. self.set_time_to_absolute()
  61. self.absolute_time.set_granularity(granularity)
  62. elif temporal_type == "relative":
  63. self.set_time_to_relative()
  64. self.relative_time.set_granularity(granularity)
  65. else:
  66. core.fatal(_("Unknown temporal type \"%s\"") % (temporal_type))
  67. self.base.set_semantic_type(semantic_type)
  68. self.metadata.set_title(title)
  69. self.metadata.set_description(description)
  70. def get_initial_values(self):
  71. """Return the initial values: granularity, temporal_type, semantic_type, title, description"""
  72. temporal_type = self.get_temporal_type()
  73. if temporal_type == "absolute":
  74. granularity = self.absolute_time.get_granularity()
  75. elif temporal_type == "relative":
  76. granularity = self.relative_time.get_granularity()
  77. semantic_type = self.base.get_semantic_type()
  78. title = self.metadata.get_title()
  79. description = self.metadata.get_description()
  80. return granularity, temporal_type, semantic_type, title, description
  81. def print_temporal_relation_matrix(self, dbif=None):
  82. """Print the temporal relation matrix of all registered maps to stdout
  83. The temproal relation matrix includes the temporal relations between
  84. all registered maps. The relations are strings stored in a list of lists.
  85. @param dbif: The database interface to be used
  86. """
  87. connect = False
  88. if dbif == None:
  89. dbif = sql_database_interface()
  90. dbif.connect()
  91. connect = True
  92. matrix = []
  93. maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
  94. for map in maps:
  95. print map.get_id(),
  96. print " "
  97. for mapA in maps:
  98. for mapB in maps:
  99. print mapA.temporal_relation(mapB),
  100. print " "
  101. if connect == True:
  102. dbif.close()
  103. def get_temporal_relation_matrix(self, dbif=None):
  104. """Return the temporal relation matrix of all registered maps as listof lists
  105. The temproal relation matrix includes the temporal relations between
  106. all registered maps. The relations are strings stored in a list of lists.
  107. @param dbif: The database interface to be used
  108. """
  109. connect = False
  110. if dbif == None:
  111. dbif = sql_database_interface()
  112. dbif.connect()
  113. connect = True
  114. matrix = []
  115. maps = self.get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
  116. # Create the temporal relation matrix
  117. # Add the map names first
  118. row = []
  119. for map in maps:
  120. row.append(map.get_id())
  121. matrix.append(row)
  122. for mapA in maps:
  123. row = []
  124. for mapB in maps:
  125. row.append(mapA.temporal_relation(mapB))
  126. matrix.append(row)
  127. if connect == True:
  128. dbif.close()
  129. return matrix
  130. def get_registered_maps_as_objects(self, where = None, order = None, dbif=None):
  131. """Return all registered maps as ordered object list
  132. @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
  133. @param order: The SQL order statement to be used to order the objects in the list without "ORDER BY"
  134. @param dbif: The database interface to be used
  135. In case nothing found None is returned
  136. """
  137. connect = False
  138. if dbif == None:
  139. dbif = sql_database_interface()
  140. dbif.connect()
  141. connect = True
  142. obj_list = []
  143. rows = self.get_registered_maps("id", where, order, dbif)
  144. if rows:
  145. for row in rows:
  146. map = self.get_new_map_instance(row["id"])
  147. map.select(dbif)
  148. obj_list.append(copy.copy(map))
  149. if connect == True:
  150. dbif.close()
  151. return obj_list
  152. def get_registered_maps(self, columns=None, where = None, order = None, dbif=None):
  153. """Return sqlite rows of all registered maps.
  154. Each row includes all columns specified in the datatype specific view
  155. @param columns: Columns to be selected as SQL compliant string
  156. @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
  157. @param order: The SQL order statement to be used to order the objects in the list without "ORDER BY"
  158. @param dbif: The database interface to be used
  159. In case nothing found None is returned
  160. """
  161. connect = False
  162. if dbif == None:
  163. dbif = sql_database_interface()
  164. dbif.connect()
  165. connect = True
  166. rows = None
  167. if self.get_map_register():
  168. # Use the correct temporal table
  169. if self.get_temporal_type() == "absolute":
  170. map_view = self.get_new_map_instance(None).get_type() + "_view_abs_time"
  171. else:
  172. map_view = self.get_new_map_instance(None).get_type() + "_view_rel_time"
  173. if columns:
  174. sql = "SELECT %s FROM %s WHERE %s.id IN (SELECT id FROM %s)" % (columns, map_view, map_view, self.get_map_register())
  175. else:
  176. sql = "SELECT * FROM %s WHERE %s.id IN (SELECT id FROM %s)" % (map_view, map_view, self.get_map_register())
  177. if where:
  178. sql += " AND %s" % (where)
  179. if order:
  180. sql += " ORDER BY %s" % (order)
  181. try:
  182. dbif.cursor.execute(sql)
  183. rows = dbif.cursor.fetchall()
  184. except:
  185. if connect == True:
  186. dbif.close()
  187. core.error(_("Unable to get map ids from register table <%s>") % (self.get_map_register()))
  188. raise
  189. if connect == True:
  190. dbif.close()
  191. return rows
  192. def delete(self, dbif=None):
  193. """Delete a space time dataset from the temporal database
  194. This method removes the space time dataset from the temporal database and drops its map register table
  195. @param dbif: The database interface to be used
  196. """
  197. # First we need to check if maps are registered in this dataset and
  198. # unregister them
  199. core.verbose(_("Delete space time %s dataset <%s> from temporal database") % (self.get_new_map_instance(ident=None).get_type(), self.get_id()))
  200. connect = False
  201. if dbif == None:
  202. dbif = sql_database_interface()
  203. dbif.connect()
  204. connect = True
  205. # SELECT all needed informations from the database
  206. self.select(dbif)
  207. core.verbose(_("Drop map register table: %s") % (self.get_map_register()))
  208. if self.get_map_register():
  209. rows = self.get_registered_maps("id", None, None, dbif)
  210. # Unregister each registered map in the table
  211. if rows:
  212. for row in rows:
  213. # Unregister map
  214. map = self.get_new_map_instance(row["id"])
  215. self.unregister_map(map, dbif)
  216. try:
  217. # Drop the map register table
  218. sql = "DROP TABLE " + self.get_map_register()
  219. dbif.cursor.execute(sql)
  220. dbif.connection.commit()
  221. except:
  222. if connect == True:
  223. dbif.close()
  224. core.error(_("Unable to drop table <%s>") % (self.get_map_register()))
  225. raise
  226. # Remove the primary key, the foreign keys will be removed by trigger
  227. self.base.delete(dbif)
  228. self.reset(None)
  229. if connect == True:
  230. dbif.close()
  231. def register_map(self, map, dbif=None):
  232. """ Register a map in the space time dataset.
  233. This method takes care of the registration of a map
  234. in a space time dataset.
  235. In case the map is already registered this function will break with a warning
  236. and return False
  237. @param dbif: The database interface to be used
  238. """
  239. connect = False
  240. if dbif == None:
  241. dbif = sql_database_interface()
  242. dbif.connect()
  243. connect = True
  244. if map.is_in_db(dbif) == False:
  245. dbif.close()
  246. core.fatal(_("Only maps with absolute or relative valid time can be registered"))
  247. core.verbose(_("Register %s map <%s> in space time %s dataset <%s>") % (map.get_type(), map.get_id(), map.get_type(), self.get_id()))
  248. # First select all data from the database
  249. map.select(dbif)
  250. map_id = map.base.get_id()
  251. map_name = map.base.get_name()
  252. map_mapset = map.base.get_mapset()
  253. map_register_table = map.get_stds_register()
  254. #print "Map register table", map_register_table
  255. # Get basic info
  256. stds_name = self.base.get_name()
  257. stds_mapset = self.base.get_mapset()
  258. stds_register_table = self.get_map_register()
  259. #print "STDS register table", stds_register_table
  260. if stds_mapset != map_mapset:
  261. dbif.close()
  262. core.fatal(_("Only maps from the same mapset can be registered"))
  263. # Check if map is already registred
  264. if stds_register_table:
  265. if dbmi.paramstyle == "qmark":
  266. sql = "SELECT id FROM " + stds_register_table + " WHERE id = (?)"
  267. else:
  268. sql = "SELECT id FROM " + stds_register_table + " WHERE id = (%s)"
  269. dbif.cursor.execute(sql, (map_id,))
  270. row = dbif.cursor.fetchone()
  271. # In case of no entry make a new one
  272. if row and row[0] == map_id:
  273. if connect == True:
  274. dbif.close()
  275. core.warning(_("Map <%s> is already registered.") % (map_id))
  276. return False
  277. # Create tables
  278. sql_path = get_sql_template_path()
  279. # We need to create the stmap raster register table bevor we can register the map
  280. if map_register_table == None:
  281. # Create a unique id
  282. uuid_rand = "map_" + str(uuid.uuid4()).replace("-", "")
  283. map_register_table = uuid_rand + "_" + self.get_type() + "_register"
  284. # Read the SQL template
  285. sql = open(os.path.join(sql_path, "map_stds_register_table_template.sql"), 'r').read()
  286. # Create the raster, raster3d and vector tables
  287. sql = sql.replace("GRASS_MAP", map.get_type())
  288. sql = sql.replace("MAP_NAME", map_name + "_" + map_mapset )
  289. sql = sql.replace("TABLE_NAME", uuid_rand )
  290. sql = sql.replace("MAP_ID", map_id)
  291. sql = sql.replace("STDS", self.get_type())
  292. try:
  293. if dbmi.__name__ == "sqlite3":
  294. dbif.cursor.executescript(sql)
  295. else:
  296. dbif.cursor.execute(sql)
  297. except:
  298. if connect == True:
  299. dbif.close()
  300. core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
  301. (map.get_type(), map.get_id()))
  302. raise
  303. # Set the stds register table name and put it into the DB
  304. map.set_stds_register(map_register_table)
  305. map.metadata.update(dbif)
  306. core.verbose(_("Created register table <%s> for %s map <%s>") % \
  307. (map_register_table, map.get_type(), map.get_id()))
  308. # We need to create the table and register it
  309. if stds_register_table == None:
  310. # Create table name
  311. stds_register_table = stds_name + "_" + stds_mapset + "_" + map.get_type() + "_register"
  312. # Read the SQL template
  313. sql = open(os.path.join(sql_path, "stds_map_register_table_template.sql"), 'r').read()
  314. # Create the raster, raster3d and vector tables
  315. sql = sql.replace("GRASS_MAP", map.get_type())
  316. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  317. sql = sql.replace("SPACETIME_ID", self.base.get_id())
  318. sql = sql.replace("STDS", self.get_type())
  319. sql_script = ""
  320. sql_script += "BEGIN TRANSACTION;\n"
  321. sql_script += sql
  322. sql_script += "\n"
  323. sql_script += "END TRANSACTION;"
  324. try:
  325. if dbmi.__name__ == "sqlite3":
  326. dbif.cursor.executescript(sql_script)
  327. else:
  328. dbif.cursor.execute(sql_script)
  329. dbif.connection.commit()
  330. except:
  331. if connect == True:
  332. dbif.close()
  333. core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
  334. (map.get_type(), map.get_id()))
  335. raise
  336. # Set the map register table name and put it into the DB
  337. self.set_map_register(stds_register_table)
  338. self.metadata.update(dbif)
  339. core.verbose(_("Created register table <%s> for space time %s dataset <%s>") % \
  340. (stds_register_table, map.get_type(), self.get_id()))
  341. # Register the stds in the map stds register table
  342. # Check if the entry is already there
  343. if dbmi.paramstyle == "qmark":
  344. sql = "SELECT id FROM " + map_register_table + " WHERE id = ?"
  345. else:
  346. sql = "SELECT id FROM " + map_register_table + " WHERE id = %s"
  347. dbif.cursor.execute(sql, (self.base.get_id(),))
  348. row = dbif.cursor.fetchone()
  349. # In case of no entry make a new one
  350. if row == None:
  351. if dbmi.paramstyle == "qmark":
  352. sql = "INSERT INTO " + map_register_table + " (id) " + "VALUES (?)"
  353. else:
  354. sql = "INSERT INTO " + map_register_table + " (id) " + "VALUES (%s)"
  355. #print sql
  356. dbif.cursor.execute(sql, (self.base.get_id(),))
  357. # Now put the raster name in the stds map register table
  358. if dbmi.paramstyle == "qmark":
  359. sql = "INSERT INTO " + stds_register_table + " (id) " + "VALUES (?)"
  360. else:
  361. sql = "INSERT INTO " + stds_register_table + " (id) " + "VALUES (%s)"
  362. #print sql
  363. dbif.cursor.execute(sql, (map_id,))
  364. if connect == True:
  365. dbif.close()
  366. return True
  367. def unregister_map(self, map, dbif = None):
  368. """Unregister a map from the space time dataset.
  369. This method takes care of the unregistration of a map
  370. from a space time dataset.
  371. @param map: The map object to unregister
  372. @param dbif: The database interface to be used
  373. """
  374. connect = False
  375. if dbif == None:
  376. dbif = sql_database_interface()
  377. dbif.connect()
  378. connect = True
  379. if map.is_in_db(dbif) == False:
  380. dbif.close()
  381. core.fatal(_("Unable to find map <%s> in temporal database") % (map.get_id()))
  382. core.verbose(_("Unregister %s map <%s>") % (map.get_type(), map.get_id()))
  383. # First select all data from the database
  384. map.select(dbif)
  385. map_id = map.base.get_id()
  386. map_register_table = map.get_stds_register()
  387. stds_register_table = self.get_map_register()
  388. # Check if the map is registered in the space time raster dataset
  389. if dbmi.paramstyle == "qmark":
  390. sql = "SELECT id FROM " + map_register_table + " WHERE id = ?"
  391. else:
  392. sql = "SELECT id FROM " + map_register_table + " WHERE id = %s"
  393. dbif.cursor.execute(sql, (self.base.get_id(),))
  394. row = dbif.cursor.fetchone()
  395. # Break if the map is not registered
  396. if row == None:
  397. core.warning(_("Map <%s> is not registered in space time dataset") %(map_id, self.base.get_id()))
  398. if connect == True:
  399. dbif.close()
  400. return False
  401. # Remove the space time raster dataset from the raster dataset register
  402. if map_register_table != None:
  403. if dbmi.paramstyle == "qmark":
  404. sql = "DELETE FROM " + map_register_table + " WHERE id = ?"
  405. else:
  406. sql = "DELETE FROM " + map_register_table + " WHERE id = %s"
  407. dbif.cursor.execute(sql, (self.base.get_id(),))
  408. # Remove the raster map from the space time raster dataset register
  409. if stds_register_table != None:
  410. if dbmi.paramstyle == "qmark":
  411. sql = "DELETE FROM " + stds_register_table + " WHERE id = ?"
  412. else:
  413. sql = "DELETE FROM " + stds_register_table + " WHERE id = %s"
  414. dbif.cursor.execute(sql, (map_id,))
  415. if connect == True:
  416. dbif.close()
  417. def update_from_registered_maps(self, dbif = None):
  418. """This methods updates the spatial and temporal extent as well as
  419. type specific metadata. It should always been called after maps are registered
  420. or unregistered/deleted from the space time dataset.
  421. The update of the temporal extent checks if the end time is set correctly.
  422. In case the registered maps have no valid end time (None) the maximum start time
  423. will be used. If the end time is earlier than the maximum start time, it will
  424. be replaced by the maximum start time.
  425. An other solution to automate this is to use the diactivated trigger
  426. in the SQL files. But this will result in a huge performance issue
  427. in case many maps are registred (>1000).
  428. @param dbif: The database interface to be used
  429. """
  430. core.verbose(_("Update metadata, spatial and temporal extent from all registered maps of <%s>") % (self.get_id()))
  431. # Nothing to do if the register is not present
  432. if not self.get_map_register():
  433. return
  434. connect = False
  435. if dbif == None:
  436. dbif = sql_database_interface()
  437. dbif.connect()
  438. connect = True
  439. map_time = None
  440. use_start_time = False
  441. # Get basic info
  442. stds_name = self.base.get_name()
  443. stds_mapset = self.base.get_mapset()
  444. sql_path = get_sql_template_path()
  445. #We create a transaction
  446. sql_script = ""
  447. sql_script += "BEGIN TRANSACTION;\n"
  448. # Update the spatial and temporal extent from registered maps
  449. # Read the SQL template
  450. sql = open(os.path.join(sql_path, "update_stds_spatial_temporal_extent_template.sql"), 'r').read()
  451. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  452. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  453. sql = sql.replace("SPACETIME_ID", self.base.get_id())
  454. sql = sql.replace("STDS", self.get_type())
  455. sql_script += sql
  456. sql_script += "\n"
  457. # Update type specific metadata
  458. sql = open(os.path.join(sql_path, "update_" + self.get_type() + "_metadata_template.sql"), 'r').read()
  459. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  460. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  461. sql = sql.replace("SPACETIME_ID", self.base.get_id())
  462. sql = sql.replace("STDS", self.get_type())
  463. sql_script += sql
  464. sql_script += "\n"
  465. sql_script += "END TRANSACTION;"
  466. if dbmi.__name__ == "sqlite3":
  467. dbif.cursor.executescript(sql_script)
  468. else:
  469. dbif.cursor.execute(sql_script)
  470. # Read and validate the selected end time
  471. self.select()
  472. if self.is_time_absolute():
  473. start_time, end_time, tz = self.get_absolute_time()
  474. else:
  475. start_time, end_time = self.get_relative_time()
  476. # In case no end time is set, use the maximum start time of all registered maps as end time
  477. if end_time == None:
  478. use_start_time = True
  479. else:
  480. # Check if the end time is smaller than the maximum start time
  481. if self.is_time_absolute():
  482. sql = """SELECT max(start_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN
  483. (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register);"""
  484. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  485. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  486. else:
  487. sql = """SELECT max(start_time) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
  488. (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register);"""
  489. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  490. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  491. dbif.cursor.execute(sql)
  492. row = dbif.cursor.fetchone()
  493. if row != None:
  494. # This seems to be a bug in sqlite3 Python driver
  495. if dbmi.__name__ == "sqlite3":
  496. tstring = row[0]
  497. # Convert the unicode string into the datetime format
  498. if tstring.find(":") > 0:
  499. time_format = "%Y-%m-%d %H:%M:%S"
  500. else:
  501. time_format = "%Y-%m-%d"
  502. max_start_time = datetime.strptime(tstring, time_format)
  503. else:
  504. max_start_time = row[0]
  505. if end_time < max_start_time:
  506. map_time = "mixed"
  507. use_start_time = True
  508. else:
  509. map_time = "interval"
  510. # Set the maximum start time as end time
  511. if use_start_time:
  512. if self.is_time_absolute():
  513. sql = """UPDATE STDS_absolute_time SET end_time =
  514. (SELECT max(start_time) FROM GRASS_MAP_absolute_time WHERE GRASS_MAP_absolute_time.id IN
  515. (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
  516. ) WHERE id = 'SPACETIME_ID';"""
  517. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  518. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  519. sql = sql.replace("SPACETIME_ID", self.base.get_id())
  520. sql = sql.replace("STDS", self.get_type())
  521. elif self.is_time_relative():
  522. sql = """UPDATE STDS_relative_time SET end_time =
  523. (SELECT max(start_time) FROM GRASS_MAP_relative_time WHERE GRASS_MAP_relative_time.id IN
  524. (SELECT id FROM SPACETIME_NAME_GRASS_MAP_register)
  525. ) WHERE id = 'SPACETIME_ID';"""
  526. sql = sql.replace("GRASS_MAP", self.get_new_map_instance(None).get_type())
  527. sql = sql.replace("SPACETIME_NAME", stds_name + "_" + stds_mapset )
  528. sql = sql.replace("SPACETIME_ID", self.base.get_id())
  529. sql = sql.replace("STDS", self.get_type())
  530. if dbmi.__name__ == "sqlite3":
  531. dbif.cursor.executescript(sql)
  532. else:
  533. dbif.cursor.execute(sql)
  534. if end_time == None:
  535. map_time = "point"
  536. # Set the map time type
  537. if self.is_time_absolute():
  538. self.absolute_time.select(dbif)
  539. self.metadata.select(dbif)
  540. if self.metadata.get_number_of_maps() > 0:
  541. self.absolute_time.set_map_time(map_time)
  542. else:
  543. self.absolute_time.set_map_time(None)
  544. self.absolute_time.update_all(dbif)
  545. else:
  546. self.relative_time.select(dbif)
  547. self.metadata.select(dbif)
  548. if self.metadata.get_number_of_maps() > 0:
  549. self.relative_time.set_map_time(map_time)
  550. else:
  551. self.relative_time.set_map_time(None)
  552. self.relative_time.update_all(dbif)
  553. # TODO: Compute the granularity of the dataset and update the database entry
  554. if connect == True:
  555. dbif.close()