[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