浏览代码

TGIS: enhance mapset access management (#1924)

* tgis: enhance mapset access management
Markus Metz 3 年之前
父节点
当前提交
596b459951

+ 25 - 51
python/grass/temporal/abstract_dataset.py

@@ -13,7 +13,6 @@ from abc import ABCMeta, abstractmethod
 from .core import (
     get_tgis_message_interface,
     init_dbif,
-    get_enable_mapset_check,
     get_current_mapset,
 )
 from .temporal_topology_dataset_connector import TemporalTopologyDatasetConnector
@@ -354,7 +353,7 @@ class AbstractDataset(
         """Return the spatial extent"""
         return self.spatial_extent
 
-    def select(self, dbif=None):
+    def select(self, dbif=None, mapset=None):
         """Select temporal dataset entry from database and fill
         the internal structure
 
@@ -363,27 +362,33 @@ class AbstractDataset(
         from the temporal database.
 
         :param dbif: The database interface to be used
+        :param mapset: The dbif connection to be used
         """
 
         dbif, connection_state_changed = init_dbif(dbif)
 
-        self.base.select(dbif)
-        self.temporal_extent.select(dbif)
-        self.spatial_extent.select(dbif)
-        self.metadata.select(dbif)
+        # default mapset is mapset of this instance
+        if mapset is None:
+            mapset = self.get_mapset()
+
+        self.base.select(dbif, mapset=mapset)
+        self.temporal_extent.select(dbif, mapset=mapset)
+        self.spatial_extent.select(dbif, mapset=mapset)
+        self.metadata.select(dbif, mapset=mapset)
         if self.is_stds() is False:
-            self.stds_register.select(dbif)
+            self.stds_register.select(dbif, mapset=mapset)
 
         if connection_state_changed:
             dbif.close()
 
-    def is_in_db(self, dbif=None):
+    def is_in_db(self, dbif=None, mapset=None):
         """Check if the dataset is registered in the database
 
         :param dbif: The database interface to be used
+        :param mapset: The dbif connection to be used
         :return: True if the dataset is registered in the database
         """
-        return self.base.is_in_db(dbif)
+        return self.base.is_in_db(dbif, mapset)
 
     @abstractmethod
     def delete(self):
@@ -400,22 +405,17 @@ class AbstractDataset(
                  empty string otherwise
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
-            self.msgr.fatal(
-                _(
-                    "Unable to insert dataset <%(ds)s> of type "
-                    "%(type)s in the temporal database. The mapset "
-                    "of the dataset does not match the current "
-                    "mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
-            )
+        # it must be possible to insert a map from a different
+        # mapset in the temporal database of the current mapset
+        # the temporal database must be in the current mapset
 
         dbif, connection_state_changed = init_dbif(dbif)
 
+        self.msgr.debug(2, "AbstractDataset.insert...")
+
+        # only modify database in current mapset
+        mapset = get_current_mapset()
+
         # Build the INSERT SQL statement
         statement = self.base.get_insert_statement_mogrified(dbif)
         statement += self.temporal_extent.get_insert_statement_mogrified(dbif)
@@ -424,8 +424,10 @@ class AbstractDataset(
         if self.is_stds() is False:
             statement += self.stds_register.get_insert_statement_mogrified(dbif)
 
+        self.msgr.debug(2, "insert with %s" % statement)
         if execute:
-            dbif.execute_transaction(statement)
+            # database to be modified must be in the current mapset
+            dbif.execute_transaction(statement, mapset=mapset)
             if connection_state_changed:
                 dbif.close()
             return ""
@@ -447,20 +449,6 @@ class AbstractDataset(
                  empty string otherwise
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
-            self.msgr.fatal(
-                _(
-                    "Unable to update dataset <%(ds)s> of type "
-                    "%(type)s in the temporal database. The mapset "
-                    "of the dataset does not match the current "
-                    "mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
-            )
-
         dbif, connection_state_changed = init_dbif(dbif)
 
         # Build the UPDATE SQL statement
@@ -495,20 +483,6 @@ class AbstractDataset(
                  empty string otherwise
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
-            self.msgr.fatal(
-                _(
-                    "Unable to update dataset <%(ds)s> of type "
-                    "%(type)s in the temporal database. The mapset"
-                    " of the dataset does not match the current "
-                    "mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
-            )
-
         dbif, connection_state_changed = init_dbif(dbif)
 
         # Build the UPDATE SQL statement

+ 25 - 35
python/grass/temporal/abstract_map_dataset.py

@@ -919,24 +919,17 @@ class AbstractMapDataset(AbstractDataset):
         :return: The SQL statements if execute=False, else an empty string,
                  None in case of a failure
         """
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
-            self.msgr.fatal(
-                _(
-                    "Unable to delete dataset <%(ds)s> of type "
-                    "%(type)s from the temporal database. The mapset"
-                    " of the dataset does not match the current "
-                    "mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
-            )
+
+        # TODO: it must be possible to delete a map from a temporal
+        # database even if the map is in a different mapset,
+        # as long as the temporal database of the current mapset is used
+
+        mapset = get_current_mapset()
 
         dbif, connection_state_changed = init_dbif(dbif)
         statement = ""
 
-        if self.is_in_db(dbif):
+        if self.is_in_db(dbif, mapset=mapset):
 
             # SELECT all needed information from the database
             self.metadata.select(dbif)
@@ -954,7 +947,7 @@ class AbstractMapDataset(AbstractDataset):
             statement += self.base.get_delete_statement()
 
         if execute:
-            dbif.execute_transaction(statement)
+            dbif.execute_transaction(statement, mapset=mapset)
             statement = ""
 
         # Remove the timestamp from the file system
@@ -1002,25 +995,13 @@ class AbstractMapDataset(AbstractDataset):
                 % {"type": self.get_type(), "map": self.get_map_id()},
             )
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
-            self.msgr.fatal(
-                _(
-                    "Unable to unregister dataset <%(ds)s> of type "
-                    "%(type)s from the temporal database. The mapset"
-                    " of the dataset does not match the current "
-                    "mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
-            )
+        mapset = get_current_mapset()
 
         statement = ""
         dbif, connection_state_changed = init_dbif(dbif)
 
         # Get all datasets in which this map is registered
-        datasets = self.get_registered_stds(dbif)
+        datasets = self.get_registered_stds(dbif, mapset=mapset)
 
         # For each stds in which the map is registered
         if datasets is not None:
@@ -1036,7 +1017,7 @@ class AbstractMapDataset(AbstractDataset):
                     stds.update_from_registered_maps(dbif)
 
         if execute:
-            dbif.execute_transaction(statement)
+            dbif.execute_transaction(statement, mapset=mapset)
             statement = ""
 
         if connection_state_changed:
@@ -1044,7 +1025,7 @@ class AbstractMapDataset(AbstractDataset):
 
         return statement
 
-    def get_registered_stds(self, dbif=None):
+    def get_registered_stds(self, dbif=None, mapset=None):
         """Return all space time dataset ids in which this map is registered
         as as a list of strings, or None if this map is not
         registered in any space time dataset.
@@ -1055,7 +1036,7 @@ class AbstractMapDataset(AbstractDataset):
         """
         dbif, connection_state_changed = init_dbif(dbif)
 
-        self.stds_register.select(dbif)
+        self.stds_register.select(dbif, mapset)
         datasets = self.stds_register.get_registered_stds()
 
         if datasets is not None and datasets != "" and datasets.find("@") >= 0:
@@ -1068,6 +1049,8 @@ class AbstractMapDataset(AbstractDataset):
 
         return datasets
 
+    # this fn should not be in a class for maps,
+    # but instead in a class for stds: AbstractSpaceTimeDataset ?
     def add_stds_to_register(self, stds_id, dbif=None, execute=True):
         """Add a new space time dataset to the register
 
@@ -1080,9 +1063,13 @@ class AbstractMapDataset(AbstractDataset):
 
         :return: The SQL statements if execute=False, else an empty string
         """
+        self.msgr.debug(2, "AbstractMapDataset.add_stds_to_register")
+
         dbif, connection_state_changed = init_dbif(dbif=dbif)
 
-        datasets = self.get_registered_stds(dbif=dbif)
+        # only modify database in current mapset
+        mapset = get_current_mapset()
+        datasets = self.get_registered_stds(dbif=dbif, mapset=mapset)
 
         if stds_id is None or stds_id == "":
             return ""
@@ -1104,7 +1091,7 @@ class AbstractMapDataset(AbstractDataset):
         statement = ""
 
         if execute is True:
-            self.stds_register.update(dbif=dbif)
+            self.stds_register.update(dbif=dbif, mapset=mapset)
         else:
             statement = self.stds_register.get_update_statement_mogrified(dbif=dbif)
 
@@ -1126,9 +1113,12 @@ class AbstractMapDataset(AbstractDataset):
 
         :return: The SQL statements if execute=False, else an empty string
         """
+        self.msgr.debug(2, "AbstractMapDataset.remove_stds_from_register")
         dbif, connection_state_changed = init_dbif(dbif)
 
-        datasets = self.get_registered_stds(dbif=dbif)
+        # only modify database in current mapset
+        mapset = get_current_mapset()
+        datasets = self.get_registered_stds(dbif=dbif, mapset=mapset)
 
         # Check if no datasets are present
         if datasets is None:

+ 37 - 51
python/grass/temporal/abstract_space_time_dataset.py

@@ -21,7 +21,6 @@ from .core import (
     get_sql_template_path,
     get_tgis_metadata,
     get_current_mapset,
-    get_enable_mapset_check,
     get_tgis_db_version_from_metadata,
 )
 from .abstract_dataset import AbstractDataset, AbstractDatasetComparisonKeyStartTime
@@ -1768,15 +1767,12 @@ class AbstractSpaceTimeDataset(AbstractDataset):
                 granularity
 
         """
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to shift dataset <%(ds)s> of type "
                     "%(type)s in the temporal database. The mapset "
-                    "of the dataset does not match the current "
+                    "of the database does not match the current "
                     "mapset"
                 )
                 % ({"ds": self.get_id()}, {"type": self.get_type()})
@@ -1946,15 +1942,12 @@ class AbstractSpaceTimeDataset(AbstractDataset):
 
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to snap dataset <%(ds)s> of type "
                     "%(type)s in the temporal database. The mapset "
-                    "of the dataset does not match the current "
+                    "of the database does not match the current "
                     "mapset"
                 )
                 % ({"ds": self.get_id()}, {"type": self.get_type()})
@@ -2056,15 +2049,12 @@ class AbstractSpaceTimeDataset(AbstractDataset):
         :param dbif: The database interface to be used
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to rename dataset <%(ds)s> of type "
                     "%(type)s in the temporal database. The mapset "
-                    "of the dataset does not match the current "
+                    "of the database does not match the current "
                     "mapset"
                 )
                 % ({"ds": self.get_id()}, {"type": self.get_type()})
@@ -2148,15 +2138,12 @@ class AbstractSpaceTimeDataset(AbstractDataset):
             % (self.get_new_map_instance(ident=None).get_type(), self.get_id())
         )
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to delete dataset <%(ds)s> of type "
                     "%(type)s from the temporal database. The mapset"
-                    " of the dataset does not match the current "
+                    " of the database does not match the current "
                     "mapset"
                 )
                 % {"ds": self.get_id(), "type": self.get_type()}
@@ -2212,6 +2199,8 @@ class AbstractSpaceTimeDataset(AbstractDataset):
 
         is_registered = False
 
+        # TODO: use mapset of the corresponding stds
+
         # Check if map is already registered
         if stds_register_table is not None:
             if dbif.get_dbmi().paramstyle == "qmark":
@@ -2249,14 +2238,14 @@ class AbstractSpaceTimeDataset(AbstractDataset):
         :return: True if success, False otherwise
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        # only modify database in current mapset
+        mapset = get_current_mapset()
+
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to register map in dataset <%(ds)s> of "
-                    "type %(type)s. The mapset of the dataset does "
+                    "type %(type)s. The mapset of the database does "
                     "not match the current mapset"
                 )
                 % {"ds": self.get_id(), "type": self.get_type()}
@@ -2264,7 +2253,7 @@ class AbstractSpaceTimeDataset(AbstractDataset):
 
         dbif, connection_state_changed = init_dbif(dbif)
 
-        if map.is_in_db(dbif) is False:
+        if map.is_in_db(dbif, mapset=self.get_mapset()) is False:
             dbif.close()
             self.msgr.fatal(
                 _(
@@ -2295,8 +2284,8 @@ class AbstractSpaceTimeDataset(AbstractDataset):
                 % (map.get_type(), map.get_map_id(), map.get_type(), self.get_id()),
             )
 
-        # First select all data from the database
-        map.select(dbif)
+        # First select all data from the database in the current mapset
+        map.select(dbif, mapset=mapset)
 
         if not map.check_for_correct_time():
             if map.get_layer():
@@ -2390,9 +2379,11 @@ class AbstractSpaceTimeDataset(AbstractDataset):
                     % {"id": self.get_id(), "map": map.get_map_id()}
                 )
 
-        if get_enable_mapset_check() is True and stds_mapset != map_mapset:
+        if stds_mapset != mapset:
             dbif.close()
-            self.msgr.fatal(_("Only maps from the same mapset can be registered"))
+            self.msgr.fatal(
+                _("Maps can only registered in a database in the current mapset")
+            )
 
         # Check if map is already registered
         if self.is_map_registered(map_id, dbif=dbif):
@@ -2421,7 +2412,8 @@ class AbstractSpaceTimeDataset(AbstractDataset):
         statement += dbif.mogrify_sql_statement((sql, (map_id,)))
 
         # Now execute the insert transaction
-        dbif.execute_transaction(statement)
+        # only databases in the current mapset can be modified
+        dbif.execute_transaction(statement, mapset=stds_mapset)
 
         if connection_state_changed:
             dbif.close()
@@ -2448,18 +2440,14 @@ class AbstractSpaceTimeDataset(AbstractDataset):
                 string, None in case of a failure
         """
 
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+        # only modify database in current mapset
+        mapset = get_current_mapset()
+
+        if self.get_mapset() != mapset:
+            self.msgr.debug(1, "STDS name <%s>" % self.get_name())
+            dbif.close()
             self.msgr.fatal(
-                _(
-                    "Unable to unregister map from dataset <%(ds)s>"
-                    " of type %(type)s in the temporal database."
-                    " The mapset of the dataset does not match the"
-                    " current mapset"
-                )
-                % {"ds": self.get_id(), "type": self.get_type()}
+                _("Maps can only unregistered in a database in the current mapset")
             )
 
         statement = ""
@@ -2509,7 +2497,7 @@ class AbstractSpaceTimeDataset(AbstractDataset):
             statement += dbif.mogrify_sql_statement((sql, (map.get_id(),)))
 
         if execute:
-            dbif.execute_transaction(statement)
+            dbif.execute_transaction(statement, mapset=mapset)
             statement = ""
 
         if connection_state_changed:
@@ -2535,15 +2523,13 @@ class AbstractSpaceTimeDataset(AbstractDataset):
 
         :param dbif: The database interface to be used
         """
-        if (
-            get_enable_mapset_check() is True
-            and self.get_mapset() != get_current_mapset()
-        ):
+
+        if self.get_mapset() != get_current_mapset():
             self.msgr.fatal(
                 _(
                     "Unable to update dataset <%(ds)s> of type "
                     "%(type)s in the temporal database. The mapset"
-                    " of the dataset does not match the current "
+                    " of the database does not match the current "
                     "mapset"
                 )
                 % {"ds": self.get_id(), "type": self.get_type()}
@@ -2614,7 +2600,7 @@ class AbstractSpaceTimeDataset(AbstractDataset):
         sql_script += sql
         sql_script += "\n"
 
-        dbif.execute_transaction(sql_script)
+        dbif.execute_transaction(sql_script, mapset=self.base.mapset)
 
         # Read and validate the selected end time
         self.select(dbif)
@@ -2694,7 +2680,7 @@ class AbstractSpaceTimeDataset(AbstractDataset):
                 sql = sql.replace("SPACETIME_ID", self.base.get_id())
                 sql = sql.replace("STDS", self.get_type())
 
-            dbif.execute_transaction(sql)
+            dbif.execute_transaction(sql, mapset=self.base.mapset)
 
         # Count the temporal map types
         maps = self.get_registered_maps_as_objects(dbif=dbif)

+ 56 - 27
python/grass/temporal/base.py

@@ -30,6 +30,7 @@ from .core import (
     get_tgis_message_interface,
     get_tgis_dbmi_paramstyle,
     SQLDatabaseInterfaceConnection,
+    get_current_mapset,
 )
 
 ###############################################################################
@@ -288,12 +289,15 @@ class SQLDatabaseInterface(DictSQLSerializer):
         sql = self.get_delete_statement()
         # print(sql)
 
+        # must use the temporal database of the current mapset,
+        # also if the map to be deleted is in a different mapset
+        mapset = get_current_mapset()
         if dbif:
-            dbif.execute(sql, mapset=self.mapset)
+            dbif.execute(sql, mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.execute(sql, mapset=self.mapset)
+            dbif.execute(sql, mapset=mapset)
             dbif.close()
 
     def get_is_in_db_statement(self):
@@ -309,25 +313,32 @@ class SQLDatabaseInterface(DictSQLSerializer):
             + "';\n"
         )
 
-    def is_in_db(self, dbif=None):
+    def is_in_db(self, dbif=None, mapset=None):
         """Check if this object is present in the temporal database
 
         :param dbif: The database interface to be used,
                      if None a temporary connection will be established
+        :param mapset: The mapset with a temporal database to be used
+                       The mapset of the database can be different from
+                       the mapset of the map
         :return: True if this object is present in the temporal database,
                  False otherwise
         """
 
         sql = self.get_is_in_db_statement()
 
+        # default: search temporal database in the mapset of the map
+        if mapset is None:
+            mapset = self.mapset
+
         if dbif:
-            dbif.execute(sql, mapset=self.mapset)
-            row = dbif.fetchone(mapset=self.mapset)
+            dbif.execute(sql, mapset=mapset)
+            row = dbif.fetchone(mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.execute(sql, mapset=self.mapset)
-            row = dbif.fetchone(mapset=self.mapset)
+            dbif.execute(sql, mapset=mapset)
+            row = dbif.fetchone(mapset=mapset)
             dbif.close()
 
         # Nothing found
@@ -359,7 +370,7 @@ class SQLDatabaseInterface(DictSQLSerializer):
             self.get_select_statement(), mapset=self.mapset
         )
 
-    def select(self, dbif=None):
+    def select(self, dbif=None, mapset=None):
         """Select the content from the temporal database and store it
         in the internal dictionary structure
 
@@ -370,20 +381,26 @@ class SQLDatabaseInterface(DictSQLSerializer):
         # print(sql)
         # print(args)
 
+        # default: use the temporal database in the mapset of this map
+        if mapset is None:
+            mapset = self.mapset
+
+        self.msgr.debug(2, "SQLDatabaseInterface.select() from mapset %s" % mapset)
+
         if dbif:
             if len(args) == 0:
-                dbif.execute(sql, mapset=self.mapset)
+                dbif.execute(sql, mapset=mapset)
             else:
-                dbif.execute(sql, args, mapset=self.mapset)
-            row = dbif.fetchone(mapset=self.mapset)
+                dbif.execute(sql, args, mapset=mapset)
+            row = dbif.fetchone(mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
             if len(args) == 0:
-                dbif.execute(sql, mapset=self.mapset)
+                dbif.execute(sql, mapset=mapset)
             else:
-                dbif.execute(sql, args, mapset=self.mapset)
-            row = dbif.fetchone(mapset=self.mapset)
+                dbif.execute(sql, args, mapset=mapset)
+            row = dbif.fetchone(mapset=mapset)
             dbif.close()
 
         # Nothing found
@@ -413,9 +430,10 @@ class SQLDatabaseInterface(DictSQLSerializer):
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(
-            self.get_insert_statement(), mapset=self.mapset
-        )
+        # mapset must be the mapset of the temporal database
+        # not of the map
+        mapset = get_current_mapset()
+        return dbif.mogrify_sql_statement(self.get_insert_statement(), mapset=mapset)
 
     def insert(self, dbif=None):
         """Serialize the content of this object and store it in the temporal
@@ -428,12 +446,15 @@ class SQLDatabaseInterface(DictSQLSerializer):
         # print(sql)
         # print(args)
 
+        # use the temporal database in the current mapset
+        mapset = get_current_mapset()
+
         if dbif:
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
             dbif.close()
 
     def get_update_statement(self, ident=None):
@@ -461,11 +482,15 @@ class SQLDatabaseInterface(DictSQLSerializer):
         :param ident: The identifier to be updated, useful for renaming
         :return: The UPDATE string
         """
+
+        # use the temporal database in the current mapset
+        mapset = get_current_mapset()
+
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
         return dbif.mogrify_sql_statement(
-            self.get_update_statement(ident), mapset=self.mapset
+            self.get_update_statement(ident), mapset=mapset
         )
 
     def update(self, dbif=None, ident=None):
@@ -481,16 +506,19 @@ class SQLDatabaseInterface(DictSQLSerializer):
         if self.ident is None:
             self.msgr.fatal(_("Missing identifier"))
 
+        # use the temporal database in the current mapset
+        mapset = get_current_mapset()
+
         sql, args = self.get_update_statement(ident)
         # print(sql)
         # print(args)
 
         if dbif:
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
             dbif.close()
 
     def get_update_all_statement(self, ident=None):
@@ -522,9 +550,7 @@ class SQLDatabaseInterface(DictSQLSerializer):
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(
-            self.get_update_all_statement(ident), mapset=self.mapset
-        )
+        return dbif.mogrify_sql_statement(self.get_update_all_statement(ident))
 
     def update_all(self, dbif=None, ident=None):
         """Serialize the content of this object, including None objects,
@@ -537,16 +563,19 @@ class SQLDatabaseInterface(DictSQLSerializer):
         if self.ident is None:
             self.msgr.fatal(_("Missing identifier"))
 
+        # use the temporal database in the current mapset
+        mapset = get_current_mapset()
+
         sql, args = self.get_update_all_statement(ident)
         # print(sql)
         # print(args)
 
         if dbif:
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.execute(sql, args, mapset=self.mapset)
+            dbif.execute(sql, args, mapset=mapset)
             dbif.close()
 
 

+ 1 - 1
python/grass/temporal/core.py

@@ -264,7 +264,7 @@ def get_tgis_message_interface():
     """Return the temporal GIS message interface which is of type
     grass.pygrass.message.Messenger()
 
-    Use this message interface to print messages to stdout using the
+    Use this message interface to print messages to stderr using the
     GRASS C-library messaging system.
     """
     global message_interface

+ 2 - 2
python/grass/temporal/open_stds.py

@@ -78,8 +78,8 @@ def open_old_stds(name, type, dbif=None):
     if not sp.is_in_db(dbif):
         dbif.close()
         msgr.fatal(
-            _("Space time %(sp)s dataset <%(name)s> not found")
-            % {"sp": sp.get_new_map_instance(None).get_type(), "name": name}
+            _("Space time %(sp)s dataset <%(id)s> not found")
+            % {"sp": sp.get_new_map_instance(None).get_type(), "id": id}
         )
     # Read content from temporal database
     sp.select(dbif)

+ 25 - 8
python/grass/temporal/register.py

@@ -84,6 +84,8 @@ def register_maps_in_space_time_dataset(
 
     msgr = get_tgis_message_interface()
 
+    msgr.debug(1, "register_maps_in_space_time_dataset()")
+
     # Make sure the arguments are of type string
     if start != "" and start is not None:
         start = str(start)
@@ -118,6 +120,13 @@ def register_maps_in_space_time_dataset(
     mapset = get_current_mapset()
     dbif, connection_state_changed = init_dbif(None)
 
+    # create new stds only in the current mapset
+    # remove all connections to any other mapsets
+    # ugly hack !
+    currcon = {}
+    currcon[mapset] = dbif.connections[mapset]
+    dbif.connections = currcon
+
     # The name of the space time dataset is optional
     if name:
         sp = open_old_stds(name, type, dbif)
@@ -147,7 +156,13 @@ def register_maps_in_space_time_dataset(
         # Build the map list again with the ids
         for count in range(len(maplist)):
             row = {}
-            mapid = AbstractMapDataset.build_id(maplist[count], mapset, None)
+            mapname = maplist[count]
+            map_mapset = mapset
+            if "@" not in mapname:
+                found = gscript.find_file(element=type, name=mapname)
+                if found["mapset"] is not None and len(found["mapset"]) > 0:
+                    map_mapset = found["mapset"]
+            mapid = AbstractMapDataset.build_id(mapname, map_mapset, None)
 
             row["id"] = mapid
             maplist[count] = row
@@ -206,7 +221,12 @@ def register_maps_in_space_time_dataset(
                 # case-sensitive, the user decides on the band name
                 row["semantic_label"] = line_list[idx].strip()
 
-            row["id"] = AbstractMapDataset.build_id(mapname, mapset)
+            map_mapset = mapset
+            if "@" not in mapname:
+                found = gscript.find_file(element=type, name=mapname)
+                if found["mapset"] is not None and len(found["mapset"]) > 0:
+                    map_mapset = found["mapset"]
+            row["id"] = AbstractMapDataset.build_id(mapname, map_mapset)
 
             maplist.append(row)
 
@@ -233,7 +253,7 @@ def register_maps_in_space_time_dataset(
     # Store the ids of datasets that must be updated
     datatsets_to_modify = {}
 
-    msgr.message(_("Gathering map information..."))
+    msgr.debug(2, "Gathering map information...")
 
     for count in range(len(maplist)):
         if count % 50 == 0:
@@ -262,8 +282,8 @@ def register_maps_in_space_time_dataset(
 
         is_in_db = False
 
-        # Put the map into the database
-        if not map.is_in_db(dbif):
+        # Put the map into the database of the current mapset
+        if not map.is_in_db(dbif, mapset):
             # Break in case no valid time is provided
             if (start == "" or start is None) and not map.has_grass_timestamp():
                 dbif.close()
@@ -434,14 +454,12 @@ def register_maps_in_space_time_dataset(
     msgr.percent(num_maps, num_maps, 1)
 
     if statement is not None and statement != "":
-        msgr.message(_("Registering maps in the temporal database..."))
         dbif.execute_transaction(statement)
 
     # Finally Register the maps in the space time dataset
     if name and map_object_list:
         count = 0
         num_maps = len(map_object_list)
-        msgr.message(_("Registering maps in the space time dataset..."))
         for map in map_object_list:
             if count % 50 == 0:
                 msgr.percent(count, num_maps, 1)
@@ -450,7 +468,6 @@ def register_maps_in_space_time_dataset(
 
     # Update the space time tables
     if name and map_object_list:
-        msgr.message(_("Updating space time dataset..."))
         sp.update_from_registered_maps(dbif)
         if update_cmd_list is True:
             sp.update_command_string(dbif=dbif)

+ 145 - 1
python/grass/temporal/testsuite/test_register_function.py

@@ -12,6 +12,7 @@ for details.
 import grass.temporal as tgis
 from grass.gunittest.case import TestCase
 from grass.gunittest.main import test
+import grass.script as gscript
 import datetime
 import os
 
@@ -78,7 +79,7 @@ class TestRasterRegisterFunctions(TestCase):
             "g.remove",
             flags="f",
             type="raster",
-            name="register_map_1,register_map_2",
+            name="register_map_1,register_map_2,register_map_null",
             quiet=True,
         )
         self.strds_abs.delete()
@@ -575,6 +576,13 @@ class TestVectorRegisterFunctions(TestCase):
             name="register_map_1,register_map_2",
             quiet=True,
         )
+        self.runModule(
+            "g.remove",
+            flags="f",
+            type="raster",
+            name="register_map_null",
+            quiet=True,
+        )
         self.stvds_abs.delete()
         self.stvds_rel.delete()
 
@@ -821,5 +829,141 @@ class TestRegisterFails(TestCase):
         )
 
 
+class TestRegisterMapsetAccess(TestCase):
+    @classmethod
+    def setUpClass(cls):
+        """Initiate the temporal GIS and set the region"""
+        os.putenv("GRASS_OVERWRITE", "1")
+        tgis.init()
+        cls.use_temp_region()
+        cls.runModule("g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0)
+
+        # Create the test maps
+        cls.runModule(
+            "r.mapcalc",
+            expression="register_map_1 = 1",
+            overwrite=True,
+            quiet=True,
+        )
+        cls.runModule(
+            "r.mapcalc",
+            expression="register_map_2 = 2",
+            overwrite=True,
+            quiet=True,
+        )
+
+        cls.del_temp_region()
+
+    def setUp(self):
+        """Create the space time raster dataset"""
+        self.strds_abs = tgis.open_new_stds(
+            name="register_test_abs",
+            type="strds",
+            temporaltype="absolute",
+            title="Test strds",
+            descr="Test strds",
+            semantic="field",
+            overwrite=True,
+        )
+        tgis.register_maps_in_space_time_dataset(
+            type="raster",
+            name=self.strds_abs.get_name(),
+            maps="register_map_1,register_map_2",
+            start="2001-01-01",
+            increment="1 day",
+            interval=True,
+        )
+
+        self.currmapset = tgis.get_current_mapset()
+        self.newmapset = "test_temporal_register_mapset_access"
+
+        # create and switch to new mapset
+        self.runModule(
+            "g.mapset",
+            mapset=self.newmapset,
+            flags="c",
+            quiet=True,
+        )
+
+        # add old mapset to search path
+        self.runModule(
+            "g.mapsets",
+            mapset=self.currmapset,
+            operation="add",
+            quiet=True,
+        )
+        self.runModule(
+            "g.mapsets",
+            flags="p",
+            verbose=True,
+        )
+
+        tgis.stop_subprocesses()
+        tgis.init()
+        self.assertNotEqual(self.currmapset, tgis.get_current_mapset())
+
+    def tearDown(self):
+        """Remove raster maps from current mapset"""
+
+        # switch to old mapset
+        self.runModule(
+            "g.mapset",
+            mapset=self.currmapset,
+            quiet=True,
+        )
+
+        tgis.stop_subprocesses()
+        tgis.init()
+
+        self.strds_abs.delete()
+
+        self.runModule(
+            "g.remove",
+            flags="f",
+            type="raster",
+            name="register_map_1,register_map_2",
+            quiet=True,
+        )
+        grassenv = gscript.gisenv()
+        mapset_path = os.path.join(
+            grassenv["GISDBASE"], grassenv["LOCATION_NAME"], self.newmapset
+        )
+        gscript.try_rmdir(mapset_path)
+
+    def test_mapset_access_1(self):
+        """Test the registration of maps from a different mapset."""
+
+        self.strds_abs_2 = tgis.open_new_stds(
+            name="register_test_abs",
+            type="strds",
+            temporaltype="absolute",
+            title="Test strds",
+            descr="Test strds",
+            semantic="field",
+            overwrite=True,
+        )
+
+        # register maps from another mapset
+        # names are not fully qualified, maps are in a different mapset
+        strdsname = self.strds_abs_2.get_name() + "@" + self.newmapset
+        maps = "register_map_1,register_map_2"
+        tgis.register_maps_in_space_time_dataset(
+            type="raster",
+            name=strdsname,
+            maps=maps,
+            start="2001-01-01",
+            increment="1 day",
+            interval=True,
+        )
+
+        self.assertModule(
+            "t.remove",
+            type="strds",
+            inputs=strdsname,
+            flags="rf",
+            quiet=True,
+        )
+
+
 if __name__ == "__main__":
     test()