[GRASS-SVN] r61984 - in grass/trunk/lib/python/temporal: . testsuite

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Sep 15 15:33:24 PDT 2014


Author: huhabla
Date: 2014-09-15 15:33:24 -0700 (Mon, 15 Sep 2014)
New Revision: 61984

Modified:
   grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
   grass/trunk/lib/python/temporal/base.py
   grass/trunk/lib/python/temporal/c_libraries_interface.py
   grass/trunk/lib/python/temporal/core.py
   grass/trunk/lib/python/temporal/gui_support.py
   grass/trunk/lib/python/temporal/list_stds.py
   grass/trunk/lib/python/temporal/register.py
   grass/trunk/lib/python/temporal/testsuite/test_register_function.py
   grass/trunk/lib/python/temporal/testsuite/test_temporal_raster3d_algebra.py
   grass/trunk/lib/python/temporal/testsuite/test_temporal_raster_algebra.py
Log:
temporal framework: Enabling mapset specific temporal databases. This feature is very experimental.

Modified: grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -350,7 +350,7 @@
             sql = sql.replace("SPACETIME_REGISTER_TABLE", stds_register_table)
             statement += sql
 
-            if dbif.dbmi.__name__ == "sqlite3":
+            if dbif.get_dbmi().__name__ == "sqlite3":
                 statement += "CREATE INDEX %s_index ON %s (id);"%(stds_register_table, stds_register_table)
 
             # Set the map register table name
@@ -1454,10 +1454,9 @@
                 sql += " AND (%s)" % (where.split(";")[0])
             if order is not None and order != "":
                 sql += " ORDER BY %s" % (order.split(";")[0])
-
             try:
-                dbif.cursor.execute(sql)
-                rows = dbif.cursor.fetchall()
+                dbif.execute(sql,  mapset=self.base.mapset)
+                rows = dbif.fetchall(mapset=self.base.mapset)
             except:
                 if connected:
                     dbif.close()
@@ -1844,7 +1843,7 @@
 
         dbif, connected = init_dbif(dbif)
 
-        if dbif.dbmi.__name__ != "sqlite3":
+        if dbif.get_dbmi().__name__ != "sqlite3":
             self.msgr.fatal(_("Renaming of space time datasets is not supported for PostgreSQL."))
 
         # SELECT all needed information from the database
@@ -1874,7 +1873,7 @@
                                                              new_map_register_table)
 
         # We need to take care of the stds index in the sqlite3 database
-        if dbif.dbmi.__name__ == "sqlite3":
+        if dbif.get_dbmi().__name__ == "sqlite3":
             statement += "DROP INDEX %s_index;\n" % (old_map_register_table)
             statement += "CREATE INDEX %s_index ON %s (id);"%(new_map_register_table,
                                                               new_map_register_table)
@@ -1970,15 +1969,15 @@
 
         # Check if map is already registered
         if stds_register_table is not None:
-            if dbif.dbmi.paramstyle == "qmark":
+            if dbif.get_dbmi().paramstyle == "qmark":
                 sql = "SELECT id FROM " + \
                     stds_register_table + " WHERE id = (?)"
             else:
                 sql = "SELECT id FROM " + \
                     stds_register_table + " WHERE id = (%s)"
             try:
-                dbif.cursor.execute(sql, (map_id,))
-                row = dbif.cursor.fetchone()
+                dbif.execute(sql, (map_id,),  mapset=self.base.mapset)
+                row = dbif.fetchone(mapset=self.base.mapset)
             except:
                 self.msgr.warning(_("Error in register table request"))
                 raise
@@ -2115,7 +2114,7 @@
                                                  dbif=dbif, execute=False)
 
         # Now put the raster name in the stds map register table
-        if dbif.dbmi.paramstyle == "qmark":
+        if dbif.get_dbmi().paramstyle == "qmark":
             sql = "INSERT INTO " + stds_register_table + \
                 " (id) " + "VALUES (?);\n"
         else:
@@ -2185,7 +2184,7 @@
         # Remove the map from the space time dataset register
         stds_register_table = self.get_map_register()
         if stds_register_table is not None:
-            if dbif.dbmi.paramstyle == "qmark":
+            if dbif.get_dbmi().paramstyle == "qmark":
                 sql = "DELETE FROM " + stds_register_table + " WHERE id = ?;\n"
             else:
                 sql = "DELETE FROM " + \
@@ -2301,12 +2300,12 @@
                     None).get_type())
                 sql = sql.replace("SPACETIME_REGISTER_TABLE", stds_register_table)
 
-            dbif.cursor.execute(sql)
-            row = dbif.cursor.fetchone()
+            dbif.execute(sql,  mapset=self.base.mapset)
+            row = dbif.fetchone(mapset=self.base.mapset)
 
             if row is not None:
                 # This seems to be a bug in sqlite3 Python driver
-                if dbif.dbmi.__name__ == "sqlite3":
+                if dbif.get_dbmi().__name__== "sqlite3":
                     tstring = row[0]
                     # Convert the unicode string into the datetime format
                     if self.is_time_absolute():

Modified: grass/trunk/lib/python/temporal/base.py
===================================================================
--- grass/trunk/lib/python/temporal/base.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/base.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -215,6 +215,7 @@
 
         >>> init()
         >>> t = SQLDatabaseInterface("raster", "soil at PERMANENT")
+        >>> t.mapset = get_current_mapset()
         >>> t.D["name"] = "soil"
         >>> t.D["mapset"] = "PERMANENT"
         >>> t.D["creator"] = "soeren"
@@ -255,6 +256,11 @@
         self.ident = ident
         self.msgr = get_tgis_message_interface()
 
+        if self.ident and self.ident.find("@") >= 0:
+            self.mapset = self.ident.split("@""")[1]
+        else:
+            self.mapset = None
+
     def get_table_name(self):
         """!Return the name of the table in which the internal
            data are inserted, updated or selected
@@ -279,11 +285,11 @@
         #print sql
 
         if dbif:
-            dbif.cursor.execute(sql)
+            dbif.execute(sql,   mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.cursor.execute(sql)
+            dbif.execute(sql,   mapset=self.mapset)
             dbif.close()
 
     def get_is_in_db_statement(self):
@@ -303,16 +309,15 @@
         """
 
         sql = self.get_is_in_db_statement()
-        #print sql
 
         if dbif:
-            dbif.cursor.execute(sql)
-            row = dbif.cursor.fetchone()
+            dbif.execute(sql, mapset=self.mapset)
+            row = dbif.fetchone(mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.cursor.execute(sql)
-            row = dbif.cursor.fetchone()
+            dbif.execute(sql, mapset=self.mapset)
+            row = dbif.fetchone(mapset=self.mapset)
             dbif.close()
 
         # Nothing found
@@ -339,7 +344,7 @@
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(self.get_select_statement())
+        return dbif.mogrify_sql_statement(self.get_select_statement(), mapset=self.mapset)
 
     def select(self, dbif=None):
         """!Select the content from the temporal database and store it
@@ -354,18 +359,18 @@
 
         if dbif:
             if len(args) == 0:
-                dbif.cursor.execute(sql)
+                dbif.execute(sql,  mapset=self.mapset)
             else:
-                dbif.cursor.execute(sql, args)
-            row = dbif.cursor.fetchone()
+                dbif.execute(sql, args,  mapset=self.mapset)
+            row = dbif.fetchone(mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
             if len(args) == 0:
-                dbif.cursor.execute(sql)
+                dbif.execute(sql, mapset=self.mapset)
             else:
-                dbif.cursor.execute(sql, args)
-            row = dbif.cursor.fetchone()
+                dbif.execute(sql, args, mapset=self.mapset)
+            row = dbif.fetchone(mapset=self.mapset)
             dbif.close()
 
         # Nothing found
@@ -396,7 +401,7 @@
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(self.get_insert_statement())
+        return dbif.mogrify_sql_statement(self.get_insert_statement(), mapset=self.mapset)
 
     def insert(self, dbif=None):
         """!Serialize the content of this object and store it in the temporal
@@ -410,11 +415,11 @@
         #print args
 
         if dbif:
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
             dbif.close()
 
     def get_update_statement(self, ident=None):
@@ -443,7 +448,7 @@
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(self.get_update_statement(ident))
+        return dbif.mogrify_sql_statement(self.get_update_statement(ident), mapset=self.mapset)
 
     def update(self, dbif=None, ident=None):
         """!Serialize the content of this object and update it in the temporal
@@ -463,11 +468,11 @@
         #print args
 
         if dbif:
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
             dbif.close()
 
     def get_update_all_statement(self, ident=None):
@@ -495,7 +500,7 @@
         if not dbif:
             dbif = SQLDatabaseInterfaceConnection()
 
-        return dbif.mogrify_sql_statement(self.get_update_all_statement(ident))
+        return dbif.mogrify_sql_statement(self.get_update_all_statement(ident), mapset=self.mapset)
 
     def update_all(self, dbif=None, ident=None):
         """!Serialize the content of this object, including None objects,
@@ -513,11 +518,11 @@
         #print args
 
         if dbif:
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
         else:
             dbif = SQLDatabaseInterfaceConnection()
             dbif.connect()
-            dbif.cursor.execute(sql, args)
+            dbif.execute(sql, args, mapset=self.mapset)
             dbif.close()
 
 ###############################################################################

Modified: grass/trunk/lib/python/temporal/c_libraries_interface.py
===================================================================
--- grass/trunk/lib/python/temporal/c_libraries_interface.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/c_libraries_interface.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -16,7 +16,7 @@
 """
 
 import sys
-from multiprocessing import Process, Lock, Pipe
+from multiprocessing import Process, Lock, Pipe,  Queue
 import logging
 from ctypes import *
 from core import *
@@ -27,6 +27,7 @@
 import grass.lib.date as libdate
 import grass.lib.raster3d as libraster3d
 import grass.lib.temporal as libtgis
+import signal, os
 
 ###############################################################################
 
@@ -43,6 +44,10 @@
     AVAILABLE_MAPSETS = 8
     GET_DRIVER_NAME = 9
     GET_DATABASE_NAME = 10
+    G_MAPSET = 11
+    G_LOCATION = 12
+    G_GISDBASE = 13
+    G_FATAL_ERROR = 14
 
     TYPE_RASTER=0
     TYPE_RASTER3D=1
@@ -50,6 +55,46 @@
 
 ###############################################################################
 
+def _fatal_error(lock, conn, data):
+    """Calls G_fatal_error()"""
+    libgis.G_fatal_error("Fatal Error in C library server")
+
+def _get_mapset(lock, conn, data):
+    """Return the current mapset
+    
+       :param lock: A multiprocessing.Lock instance
+       :param conn: A multiprocessing.Pipe instance used to send True or False
+       :param data: The mapset as list entry 1 [function_id]
+       
+       :returns: Name of the current mapset
+    """    
+    mapset = libgis.G_mapset()
+    conn.send(mapset) 
+    
+def _get_location(lock, conn, data):
+    """Return the current location
+    
+       :param lock: A multiprocessing.Lock instance
+       :param conn: A multiprocessing.Pipe instance used to send True or False
+       :param data: The mapset as list entry 1 [function_id]
+       
+       :returns: Name of the location
+    """    
+    location = libgis.G_location()
+    conn.send(location) 
+   
+def _get_gisdbase(lock, conn, data):
+    """Return the current gisdatabase
+    
+       :param lock: A multiprocessing.Lock instance
+       :param conn: A multiprocessing.Pipe instance used to send True or False
+       :param data: The mapset as list entry 1 [function_id]
+       
+       :returns: Name of the gisdatabase
+    """    
+    gisdbase = libgis.G_gisdbase()
+    conn.send(gisdbase) 
+
 def _get_driver_name(lock, conn, data):
     """Return the temporal database driver of a specific mapset
     
@@ -59,9 +104,11 @@
        
        :returns: Name of the driver or None if no temporal database present
     """
+    mapset = data[1]
+    if not mapset:
+        mapset = libgis.G_mapset()
     
-    drstring = libtgis.tgis_get_mapset_driver_name(data[1])
-    
+    drstring = libtgis.tgis_get_mapset_driver_name(mapset)
     conn.send(drstring) 
 
 ###############################################################################
@@ -75,13 +122,17 @@
        
        :returns: Name of the database or None if no temporal database present
     """
-    dbstring = libtgis.tgis_get_mapset_database_name(data[1])
+    mapset = data[1]
+    if not mapset:
+        mapset = libgis.G_mapset()
+    dbstring = libtgis.tgis_get_mapset_database_name(mapset)
+
     if dbstring:
         # We substitute GRASS variables if they are located in the database string
         # This behavior is in conjunction with db.connect
-        dbstring = dbstring.replace("$GISDBASE", corefunc.current_gisdbase)
-        dbstring = dbstring.replace("$LOCATION_NAME", corefunc.current_location)
-        dbstring = dbstring.replace("$MAPSET", corefunc.current_mapset)
+        dbstring = dbstring.replace("$GISDBASE", libgis.G_gisdbase())
+        dbstring = dbstring.replace("$LOCATION_NAME", libgis.G_location())
+        dbstring = dbstring.replace("$MAPSET", libgis.G_mapset())
     conn.send(dbstring) 
 
 ###############################################################################
@@ -649,12 +700,15 @@
 ###############################################################################
 
 def _stop(lock, conn, data):
+    libgis.G_debug(1, "Stop C-interface server")
     conn.close()
     lock.release()
-    libgis.G_debug(1, "Stop C-interface server")
     sys.exit()
 
 ###############################################################################
+# Global server connection
+server_connection = None
+server_lock = None
 
 def c_library_server(lock, conn):
     """The GRASS C-libraries server function designed to be a target for
@@ -662,9 +716,9 @@
 
        :param lock: A multiprocessing.Lock
        :param conn: A multiprocessing.Pipe
-    """
+    """   
     # Crerate the function array
-    functions = [0]*11
+    functions = [0]*15
     functions[RPCDefs.STOP] = _stop
     functions[RPCDefs.HAS_TIMESTAMP] = _has_timestamp
     functions[RPCDefs.WRITE_TIMESTAMP] = _write_timestamp
@@ -675,6 +729,10 @@
     functions[RPCDefs.AVAILABLE_MAPSETS] = _available_mapsets
     functions[RPCDefs.GET_DRIVER_NAME] = _get_driver_name
     functions[RPCDefs.GET_DATABASE_NAME] = _get_database_name
+    functions[RPCDefs.G_MAPSET] = _get_mapset
+    functions[RPCDefs.G_LOCATION] = _get_location
+    functions[RPCDefs.G_GISDBASE] = _get_gisdbase
+    functions[RPCDefs.G_FATAL_ERROR] = _fatal_error
 
     libgis.G_gisinit("c_library_server")
     libgis.G_debug(1, "Start C-interface server")
@@ -807,6 +865,10 @@
        'sqlite'
        >>> ciface.get_database_name().split("/")[-1]
        'sqlite.db'
+       
+       >>> mapset = ciface.get_mapset()
+       >>> location = ciface.get_location()
+       >>> gisdbase = ciface.get_gisdbase()
 
        >>> gscript.del_temp_region()
 
@@ -815,11 +877,12 @@
     def __init__(self):
         self.client_conn = None
         self.server_conn = None
+        self.queue = None
         self.server = None
         self.start_server()
 
     def start_server(self):
-        self.client_conn, self.server_conn = Pipe()
+        self.client_conn, self.server_conn = Pipe(True)
         self.lock = Lock()
         self.server = Process(target=c_library_server, args=(self.lock,
                                                           self.server_conn))
@@ -1135,9 +1198,6 @@
            
            :returns: Name of the driver or None if no temporal database present
         """
-        if mapset is None or mapset is "":
-            mapset = corefunc.get_current_mapset()
-
         self._check_restart_server()
         self.client_conn.send([RPCDefs.GET_DRIVER_NAME, mapset])
         return self.client_conn.recv()
@@ -1149,14 +1209,47 @@
            
            :returns: Name of the database or None if no temporal database present
         """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.GET_DATABASE_NAME, mapset])
+        return self.client_conn.recv()
+    
+    def get_mapset(self):
+        """Return the current mapset
+                   
+           :returns: Name of the current mapset
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.G_MAPSET,])
+        return self.client_conn.recv()
         
-        if mapset is None or mapset is "":
-            mapset = corefunc.get_current_mapset()
+    def get_location(self):
+        """Return the location
+                   
+           :returns: Name of the location
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.G_LOCATION,])
+        return self.client_conn.recv()
         
+    def get_gisdbase(self):
+        """Return the gisdatabase
+                   
+           :returns: Name of the gisdatabase
+        """
         self._check_restart_server()
-        self.client_conn.send([RPCDefs.GET_DATABASE_NAME, mapset])
+        self.client_conn.send([RPCDefs.G_GISDBASE,])
         return self.client_conn.recv()
-    
+        
+    def fatal_error(self, mapset=None):
+        """Return the temporal database name of a specific mapset
+        
+           :param mapset: Name of the mapset
+           
+           :returns: Name of the database or None if no temporal database present
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.G_FATAL_ERROR])
+
     def stop(self):
         """Stop the messenger server and close the pipe
         

Modified: grass/trunk/lib/python/temporal/core.py
===================================================================
--- grass/trunk/lib/python/temporal/core.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/core.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -351,8 +351,8 @@
     # Select metadata if the table is present
     try:
         statement = "SELECT * FROM tgis_metadata;\n"
-        dbif.cursor.execute(statement)
-        rows = dbif.cursor.fetchall()
+        dbif.execute(statement)
+        rows = dbif.fetchall()
     except:
         rows = None
 
@@ -556,8 +556,8 @@
         if os.path.exists(tgis_database_string):
             dbif.connect()
             # Check for raster_base table
-            dbif.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='raster_base';")
-            name = dbif.cursor.fetchone()
+            dbif.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='raster_base';")
+            name = dbif.fetchone()
             if name and name[0] == "raster_base":
                 db_exists = True
             dbif.close()
@@ -565,9 +565,9 @@
         # Connect to database
         dbif.connect()
         # Check for raster_base table
-        dbif.cursor.execute("SELECT EXISTS(SELECT * FROM information_schema.tables "
+        dbif.execute("SELECT EXISTS(SELECT * FROM information_schema.tables "
                    "WHERE table_name=%s)", ('raster_base',))
-        if dbif.cursor.fetchone()[0]:
+        if dbif.fetchone()[0]:
             db_exists = True
 
     backup_howto = "The format of your actual temporal database is not supported any more.\n"\
@@ -611,7 +611,7 @@
 def get_database_info_string():
     dbif = SQLDatabaseInterfaceConnection()
 
-    info  = "\nDBMI interface:..... " + str(dbif.dbmi.__name__)
+    info  = "\nDBMI interface:..... " + str(dbif.get_dbmi().__name__)
     info += "\nTemporal database:.. " + str( get_tgis_database_string())
     return info
 
@@ -775,7 +775,138 @@
 
 ###############################################################################
 
-class SQLDatabaseInterfaceConnection():
+class SQLDatabaseInterfaceConnection(object):
+    def __init__(self):
+        self.tgis_mapsets = get_available_temporal_mapsets()
+        self.current_mapset = get_current_mapset()
+        self.connections = {}
+        self.connected = False
+        
+        self.unique_connections = {}
+        
+        for mapset in self.tgis_mapsets.keys():
+            driver,  dbstring = self.tgis_mapsets[mapset]
+            
+            if dbstring not in self.unique_connections.keys():
+                self.unique_connections[dbstring] = DBConnection(driver)
+            
+            self.connections[mapset] = self.unique_connections[dbstring]
+
+    def get_dbmi(self,  mapset=None):
+        if mapset is None:
+            mapset = self.current_mapset
+        return self.connections[mapset].dbmi
+
+    def rollback(self,  mapset=None):
+        """
+            Roll back the last transaction. This must be called
+            in case a new query should be performed after a db error.
+
+            This is only relevant for postgresql database.
+        """
+        if mapset is None:
+            mapset = self.current_mapset
+
+    def connect(self):
+        """Connect to the DBMI to execute SQL statements
+
+           Supported backends are sqlite3 and postgresql
+        """
+        for mapset in self.tgis_mapsets.keys():
+            driver,  dbstring = self.tgis_mapsets[mapset]
+            conn = self.connections[mapset]
+            if conn.is_connected() is False:
+                conn .connect(dbstring)
+                
+        self.connected = True
+        
+    def is_connected(self):
+        return self.connected
+
+    def close(self):
+        """Close the DBMI connection
+
+           There may be several temporal databases in a location, hence 
+           close all temporal databases that have been opened. 
+        """
+        for key in self.unique_connections.keys():
+            self.unique_connections[key] .close()
+        
+        self.connected = False
+
+    def mogrify_sql_statement(self, content, mapset=None):
+        """Return the SQL statement and arguments as executable SQL string
+
+           :param content: The content as tuple with two entries, the first
+                           entry is the SQL statement with DBMI specific
+                           place holder (?), the second entry is the argument
+                           list that should substitute the place holder.
+           :param mapset: The mapset of the abstract dataset or temporal
+                          database location, if None the current mapset 
+                          will be used
+        """
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].mogrify_sql_statement(content)
+
+    def check_table(self, table_name, mapset=None):
+        """Check if a table exists in the temporal database
+
+           :param table_name: The name of the table to be checked for existence
+           :param mapset: The mapset of the abstract dataset or temporal
+                          database location, if None the current mapset 
+                          will be used
+           :returns: True if the table exists, False otherwise
+           
+           TODO:
+           There may be several temporal databases in a location, hence 
+           the mapset is used to query the correct temporal database.
+        """
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].check_table(table_name)
+
+    def execute(self,  statement,  args=None,  mapset=None):
+        """""
+           :param mapset: The mapset of the abstract dataset or temporal
+                          database location, if None the current mapset 
+                          will be used
+        """
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].execute(statement,  args)
+
+    def fetchone(self,  mapset=None):
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].fetchone()
+
+    def fetchall(self,  mapset=None):
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].fetchall()
+
+    def execute_transaction(self, statement, mapset=None):
+        """Execute a transactional SQL statement
+
+           The BEGIN and END TRANSACTION statements will be added automatically
+           to the sql statement
+
+           :param statement: The executable SQL statement or SQL script
+        """
+        if mapset is None:
+            mapset = self.current_mapset
+
+        return self.connections[mapset].execute_transaction(statement)
+ 
+###############################################################################
+
+class DBConnection(object):
     """This class represents the database interface connection
        and provides access to the chisen backend modules.
 
@@ -784,31 +915,29 @@
          - postgresql via psycopg2
 
     """
-    def __init__(self):
-        """TODO:
-           Create a list of all accessible mapsets that have temporal database definitions
-           Create a database connection for each mapset, reuse existing database connections
-           in case the connection specifications are identical (a single temporal database).
-           
-           Database string and river are mapset specific, hence the driver may change with the mapset.
-        """
+    def __init__(self ,  backend=None):
         self.connected = False
-        global tgis_backend
-        if tgis_backend == "sqlite":
-            self.dbmi = sqlite3
+        if backend is None:
+            global tgis_backend
+            if tgis_backend == "sqlite":
+                self.dbmi = sqlite3
+            else:
+                self.dbmi = psycopg2
         else:
-            self.dbmi = psycopg2
+            if backend == "sqlite":
+                self.dbmi = sqlite3
+            else:
+                self.dbmi = psycopg2
 
         self.msgr = get_tgis_message_interface()
         self.msgr.debug(1, "SQLDatabaseInterfaceConnection constructor")
 
     def __del__(self):
-        """TODO:
-           Close all mapset specific connections, be aware that different 
-           mapsets may have identical connections.
-        """
         if self.connected is True:
             self.close()
+            
+    def is_connected(self):
+        return self.connected
 
     def rollback(self):
         """
@@ -821,22 +950,19 @@
             if self.connected:
                 self.connection.rollback()
 
-    def connect(self):
+    def connect(self,  dbstring=None):
         """Connect to the DBMI to execute SQL statements
 
            Supported backends are sqlite3 and postgresql
-           
-           TODO:
-           Create connections for each mapset that has a temporal database.
-           Open existing connections only once.
-           The dbmi, connection and cursor are mapset specific 
-           and must be managed in a dict.
         """
-        global tgis_database_string
+        # Connection in the current mapset
+        if dbstring is None:
+            global tgis_database_string
+            dbstring = tgis_database_string
 
         try:
             if self.dbmi.__name__ == "sqlite3":
-                self.connection = self.dbmi.connect(tgis_database_string,
+                self.connection = self.dbmi.connect(dbstring,
                         detect_types = self.dbmi.PARSE_DECLTYPES | self.dbmi.PARSE_COLNAMES)
                 self.connection.row_factory = self.dbmi.Row
                 self.connection.isolation_level = None
@@ -844,7 +970,7 @@
                 self.cursor.execute("PRAGMA synchronous = OFF")
                 self.cursor.execute("PRAGMA journal_mode = MEMORY")
             elif self.dbmi.__name__ == "psycopg2":
-                self.connection = self.dbmi.connect(tgis_database_string)
+                self.connection = self.dbmi.connect(dbstring)
                 #self.connection.set_isolation_level(dbmi.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
                 self.cursor = self.connection.cursor(
                     cursor_factory = self.dbmi.extras.DictCursor)
@@ -868,7 +994,7 @@
         self.cursor.close()
         self.connected = False
 
-    def mogrify_sql_statement(self, content, mapset=None):
+    def mogrify_sql_statement(self, content):
         """Return the SQL statement and arguments as executable SQL string
         
            TODO:
@@ -949,7 +1075,7 @@
 
                 return statement
 
-    def check_table(self, table_name, mapset=None):
+    def check_table(self, table_name):
         """Check if a table exists in the temporal database
 
            :param table_name: The name of the table to be checked for existence
@@ -987,21 +1113,39 @@
 
         return table_exists
     
-    def execute(self, statement, mapset=None):
+    def execute(self, statement,  args=None):
         """Execute a SQL statement
 
            :param statement: The executable SQL statement or SQL script
-           :param mapset: The mapset of the abstract dataset or temporal
-                          database location, if None the current mapset 
-                          will be used
-           
-           NOTE: not implemented, the purpose of this function is to
-                 replace all dbif.cursor.execute() calls in the temporal
-                 framework to allow SQL statement execution with distributed
-                 temporal databases identified by their mapset name
         """
-        pass
+        connected = False
+        if not self.connected:
+            self.connect()
+            connected = True
+        try:
+            if args:
+                self.cursor.execute(statement,  args)
+            else:
+                self.cursor.execute(statement)
+        except:
+            if connected:
+                self.close()
+            self.msgr.error(_("Unable to execute :\n %(sql)s" % {"sql":statement}))
+            raise
 
+        if connected:
+            self.close()
+        
+    def fetchone(self):
+        if self.connected:
+            return self.cursor.fetchone()
+        return None
+
+    def fetchall(self):
+        if self.connected:
+            return self.cursor.fetchall()
+        return None
+
     def execute_transaction(self, statement, mapset=None):
         """Execute a transactional SQL statement
 
@@ -1009,9 +1153,6 @@
            to the sql statement
 
            :param statement: The executable SQL statement or SQL script
-           :param mapset: The mapset of the abstract dataset or temporal
-                          database location, if None the current mapset 
-                          will be used
         """
         connected = False
         if not self.connected:
@@ -1064,7 +1205,7 @@
         dbif = SQLDatabaseInterfaceConnection()
         dbif.connect()
         return dbif, True
-    elif dbif.connected is False:
+    elif dbif.is_connected() is False:
         dbif.connect()
         return dbif, True
 

Modified: grass/trunk/lib/python/temporal/gui_support.py
===================================================================
--- grass/trunk/lib/python/temporal/gui_support.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/gui_support.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -89,27 +89,31 @@
     id = None
     sp = dataset_factory(type, id)
     dbif, connected = init_dbif(dbif)
+    
+    mapsets = get_available_temporal_mapsets()
 
     output = []
     temporal_type = ["absolute", 'relative']
     for type in temporal_type:
-        # Table name
-        if type == "absolute":
-            table = sp.get_type() + "_view_abs_time"
-        else:
-            table = sp.get_type() + "_view_rel_time"
+        # For each available mapset
+        for mapset in mapsets.keys():
+            # Table name
+            if type == "absolute":
+                table = sp.get_type() + "_view_abs_time"
+            else:
+                table = sp.get_type() + "_view_rel_time"
 
-        # Create the sql selection statement
-        sql = "SELECT id FROM " + table
-        sql += " ORDER BY id"
+            # Create the sql selection statement
+            sql = "SELECT id FROM " + table
+            sql += " ORDER BY id"
 
-        dbif.cursor.execute(sql)
-        rows = dbif.cursor.fetchall()
+            dbif.execute(sql,  mapset=mapset)
+            rows = dbif.fetchall(mapset=mapset)
 
-        # Append the ids of the space time datasets
-        for row in rows:
-            for col in row:
-                output.append(str(col))
+            # Append the ids of the space time datasets
+            for row in rows:
+                for col in row:
+                    output.append(str(col))
 
     if connected is True:
         dbif.close()

Modified: grass/trunk/lib/python/temporal/list_stds.py
===================================================================
--- grass/trunk/lib/python/temporal/list_stds.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/list_stds.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -70,11 +70,11 @@
     dbif = SQLDatabaseInterfaceConnection()
     dbif.connect()
     
-    mapsets = get_tgis_c_library_interface().available_mapsets()
+    mapsets = get_available_temporal_mapsets()
     
     result = {}
     
-    for mapset in mapsets:
+    for mapset in mapsets.keys():
         
         if temporal_type == "absolute":
             table = sp.get_type() + "_view_abs_time"
@@ -95,8 +95,8 @@
         if order:
             sql += " ORDER BY " + order
 
-        dbif.cursor.execute(sql)
-        rows = dbif.cursor.fetchall()
+        dbif.execute(sql,  mapset=mapset)
+        rows = dbif.fetchall(mapset=mapset)
         
         if rows:
             result[mapset] = rows

Modified: grass/trunk/lib/python/temporal/register.py
===================================================================
--- grass/trunk/lib/python/temporal/register.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/register.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -290,7 +290,7 @@
 
         # Sqlite3 performance is better for huge datasets when committing in
         # small chunks
-        if dbif.dbmi.__name__ == "sqlite3":
+        if dbif.get_dbmi().__name__ == "sqlite3":
             if count % 100 == 0:
                 if statement is not None and statement != "":
                     dbif.execute_transaction(statement)

Modified: grass/trunk/lib/python/temporal/testsuite/test_register_function.py
===================================================================
--- grass/trunk/lib/python/temporal/testsuite/test_register_function.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/testsuite/test_register_function.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -12,6 +12,7 @@
 import grass.temporal as tgis
 import grass.gunittest
 import datetime
+import os
 
 
 class TestRegisterFunctions(grass.gunittest.TestCase):
@@ -20,6 +21,7 @@
     def setUpClass(cls):
         """!Initiate the temporal GIS and set the region
         """
+        os.putenv("GRASS_OVERWRITE", "1")
         # Use always the current mapset as temporal database
         cls.runModule("g.gisenv", set="TGIS_USE_CURRENT_MAPSET=1")
         tgis.init()

Modified: grass/trunk/lib/python/temporal/testsuite/test_temporal_raster3d_algebra.py
===================================================================
--- grass/trunk/lib/python/temporal/testsuite/test_temporal_raster3d_algebra.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/testsuite/test_temporal_raster3d_algebra.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -13,6 +13,7 @@
 import grass.temporal as tgis
 import grass.gunittest as gunittest
 import datetime
+import os
 
 
 class TestRegisterFunctions(gunittest.TestCase):
@@ -21,6 +22,7 @@
     def setUpClass(cls):
         """!Initiate the temporal GIS and set the region
         """
+        os.putenv("GRASS_OVERWRITE", "1")
         tgis.init(True) # Raise on error instead of exit(1)
         grass.script.use_temp_region()
         ret = grass.script.run_command("g.region", n=80.0, s=0.0, e=120.0,

Modified: grass/trunk/lib/python/temporal/testsuite/test_temporal_raster_algebra.py
===================================================================
--- grass/trunk/lib/python/temporal/testsuite/test_temporal_raster_algebra.py	2014-09-15 22:29:55 UTC (rev 61983)
+++ grass/trunk/lib/python/temporal/testsuite/test_temporal_raster_algebra.py	2014-09-15 22:33:24 UTC (rev 61984)
@@ -13,6 +13,7 @@
 import grass.temporal as tgis
 import grass.gunittest as gunittest
 import datetime
+import os
 
 
 class TestRegisterFunctions(gunittest.TestCase):
@@ -21,6 +22,7 @@
     def setUpClass(cls):
         """!Initiate the temporal GIS and set the region
         """
+        os.putenv("GRASS_OVERWRITE", "1")
         tgis.init(True) # Raise on error instead of exit(1)
         grass.script.use_temp_region()
         ret = grass.script.run_command("g.region", n=80.0, s=0.0, e=120.0,



More information about the grass-commit mailing list