|
@@ -27,7 +27,7 @@ Usage:
|
|
|
|
|
|
@endcode
|
|
|
|
|
|
-(C) 2011-2013 by the GRASS Development Team
|
|
|
+(C) 2011-2014 by the GRASS Development Team
|
|
|
This program is free software under the GNU General Public
|
|
|
License (>=v2). Read the file COPYING that comes with GRASS
|
|
|
for details.
|
|
@@ -83,6 +83,22 @@ def profile_function(func):
|
|
|
# of the temporal GIS
|
|
|
# It can either be "sqlite" or "pg"
|
|
|
tgis_backend = None
|
|
|
+def get_tgis_backend():
|
|
|
+ """!Return the temporal GIS backend as string
|
|
|
+
|
|
|
+ return either "sqlite" or "pg"
|
|
|
+ """
|
|
|
+ global tgis_backend
|
|
|
+ return tgis_backend
|
|
|
+
|
|
|
+# Global variable that defines the database string
|
|
|
+# of the temporal GIS
|
|
|
+tgis_database = None
|
|
|
+def get_tgis_database():
|
|
|
+ """!Return the temporal database string specified with t.connect
|
|
|
+ """
|
|
|
+ global tgis_database
|
|
|
+ return tgis_database
|
|
|
|
|
|
# The version of the temporal framework
|
|
|
# this value must be an integer larger than 0
|
|
@@ -94,9 +110,22 @@ tgis_version=2
|
|
|
# temporal database SQL layout
|
|
|
tgis_db_version=2
|
|
|
|
|
|
+# We need to know the parameter style of the database backend
|
|
|
+tgis_dbmi_paramstyle = None
|
|
|
+
|
|
|
+def get_tgis_dbmi_paramstyle():
|
|
|
+ """!Return the temporal database backend parameter style
|
|
|
+
|
|
|
+ @return "qmark" or ""
|
|
|
+ """
|
|
|
+ global tgis_dbmi_paramstyle
|
|
|
+ return tgis_dbmi_paramstyle
|
|
|
+
|
|
|
# We need to access the current mapset quite often in the framework, so we make
|
|
|
-# global variable that will be initiated when init() is called
|
|
|
-current_mapset=None
|
|
|
+# a global variable that will be initiated when init() is called
|
|
|
+current_mapset = None
|
|
|
+current_location = None
|
|
|
+current_gisdbase = None
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -110,19 +139,29 @@ def get_current_mapset():
|
|
|
global current_mapset
|
|
|
return current_mapset
|
|
|
|
|
|
-def _set_current_mapset(mapset=None):
|
|
|
- """!This functions set the global current mapset variable to
|
|
|
- the current mapset by calling g.gisenv.
|
|
|
+###############################################################################
|
|
|
+
|
|
|
+def get_current_location():
|
|
|
+ """!Return the current location
|
|
|
|
|
|
- @param mapset The current mapset, g.gisenv will be called
|
|
|
- if this variable is set to None
|
|
|
+ This is the fastest way to receive the current location.
|
|
|
+ The current location is set by init() and stored in a global variable.
|
|
|
+ This function provides access to this global variable.
|
|
|
"""
|
|
|
- global current_mapset
|
|
|
+ global current_location
|
|
|
+ return current_location
|
|
|
+
|
|
|
+###############################################################################
|
|
|
|
|
|
- if mapset == None:
|
|
|
- mapset = core.gisenv()["MAPSET"]
|
|
|
+def get_current_gisdbase():
|
|
|
+ """!Return the current gis database (gisdbase)
|
|
|
|
|
|
- current_mapset = mapset
|
|
|
+ This is the fastest way to receive the current gisdbase.
|
|
|
+ The current gisdbase is set by init() and stored in a global variable.
|
|
|
+ This function provides access to this global variable.
|
|
|
+ """
|
|
|
+ global current_gisdbase
|
|
|
+ return current_gisdbase
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -266,47 +305,19 @@ def get_tgis_metadata(dbif=None):
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
-def get_temporal_dbmi_init_string(kv=None, grassenv=None):
|
|
|
- """!Return the database initialization string
|
|
|
+# The temporal database string set with t.connect
|
|
|
+# with substituted GRASS variables gisdbase, location and mapset
|
|
|
+tgis_database_string = None
|
|
|
|
|
|
- @param kv dictionary generated by grass.script.parse_command("t.connect", flags="pg")
|
|
|
- @param grassenv Grass environemntal variables created by grass.script.gisenv()
|
|
|
+def get_tgis_database_string():
|
|
|
+ """!Return the preprocessed temporal database string
|
|
|
+
|
|
|
+ This string is the temporal database string set with t.connect
|
|
|
+ that was processed to substitue location, gisdbase and mapset
|
|
|
+ varibales.
|
|
|
"""
|
|
|
-
|
|
|
- global temporal_dbmi_init_string
|
|
|
-
|
|
|
- if kv == None:
|
|
|
- kv = core.parse_command("t.connect", flags="pg")
|
|
|
- if grassenv == None:
|
|
|
- grassenv = core.gisenv()
|
|
|
-
|
|
|
- global tgis_backend
|
|
|
- msgr = get_tgis_message_interface()
|
|
|
-
|
|
|
- if tgis_backend == "sqlite":
|
|
|
- # We substitute GRASS variables if they are located in the database string
|
|
|
- # This behavior is in conjunction with db.connect
|
|
|
- if "database" in kv:
|
|
|
- string = kv["database"]
|
|
|
- string = string.replace("$GISDBASE", grassenv["GISDBASE"])
|
|
|
- string = string.replace(
|
|
|
- "$LOCATION_NAME", grassenv["LOCATION_NAME"])
|
|
|
- string = string.replace("$MAPSET", grassenv["MAPSET"])
|
|
|
- temporal_dbmi_init_string = string
|
|
|
- return string
|
|
|
- else:
|
|
|
- msgr.fatal(_("Unable to initialize the temporal GIS DBMI "
|
|
|
- "interface. Use t.connect to specify the driver "
|
|
|
- "and the database string"))
|
|
|
- elif tgis_backend == "pg":
|
|
|
- if "database" in kv:
|
|
|
- string = kv["database"]
|
|
|
- temporal_dbmi_init_string = string
|
|
|
- return string
|
|
|
- else:
|
|
|
- msgr.fatal(_("Unable to initialize the temporal GIS DBMI "
|
|
|
- "interface. Use t.connect to specify the driver "
|
|
|
- "and the database string"))
|
|
|
+ global tgis_database_string
|
|
|
+ return tgis_database_string
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -319,6 +330,7 @@ def get_sql_template_path():
|
|
|
|
|
|
def stop_subprocesses():
|
|
|
"""!Stop the messenger and C-interface subprocesses
|
|
|
+ that are started by tgis.init()
|
|
|
"""
|
|
|
global message_interface
|
|
|
global c_library_interface
|
|
@@ -327,55 +339,74 @@ def stop_subprocesses():
|
|
|
if c_library_interface:
|
|
|
c_library_interface.stop()
|
|
|
|
|
|
+# We register this function to be called at exit
|
|
|
atexit.register(stop_subprocesses)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
def init():
|
|
|
"""!This function set the correct database backend from GRASS environmental variables
|
|
|
- and creates the grass location database structure for raster,
|
|
|
+ and creates the grass temporal database structure for raster,
|
|
|
vector and raster3d maps as well as for the space-time datasets strds,
|
|
|
str3ds and stvds in case it does not exists.
|
|
|
-
|
|
|
+
|
|
|
Several global variables are initiated and the messenger and C-library interface
|
|
|
subprocesses are spawned.
|
|
|
-
|
|
|
- The following g.gisenv variables are checked:
|
|
|
- - TGIS_RAISE_ON_ERROR
|
|
|
- - TGIS_DISABLE_MAPSET_CHECK
|
|
|
- - TGIS_DISABLE_TIMESTAMP_WRITE
|
|
|
-
|
|
|
+
|
|
|
+ Re-run this function in case the following GRASS variables change while the process runs:
|
|
|
+ - MAPSET
|
|
|
+ - LOCATION_NAME
|
|
|
+ - GISDBASE
|
|
|
+ - TGIS_RAISE_ON_ERROR
|
|
|
+ - TGIS_DISABLE_MAPSET_CHECK
|
|
|
+ - TGIS_DISABLE_TIMESTAMP_WRITE
|
|
|
+
|
|
|
+ Re-run the script if the following t.connect variables change while the process runs:
|
|
|
+ - temporal GIS driver (set by t.connect driver=)
|
|
|
+ - temporal GIS database (set by t.connect database=)
|
|
|
+
|
|
|
The following environmental variables are checked:
|
|
|
- GRASS_TGIS_PROFILE
|
|
|
|
|
|
ATTENTION: This functions must be called before any spatio-temporal processing
|
|
|
can be started
|
|
|
"""
|
|
|
- # We need to set the correct database backend from the environment variables
|
|
|
+ # We need to set the correct database backend and several global variables
|
|
|
+ # from the GRASS mapset specific environment variables of g.gisenv and t.connect
|
|
|
global tgis_backend
|
|
|
+ global tgis_database
|
|
|
+ global tgis_database_string
|
|
|
+ global tgis_dbmi_paramstyle
|
|
|
global enable_mapset_check
|
|
|
global enable_timestamp_write
|
|
|
-
|
|
|
+ global current_mapset
|
|
|
+ global current_location
|
|
|
+ global current_gisdbase
|
|
|
+
|
|
|
+ # We must run t.connect at first to create the temporal database and to
|
|
|
+ # get the environmental variables
|
|
|
core.run_command("t.connect", flags="c")
|
|
|
kv = core.parse_command("t.connect", flags="pg")
|
|
|
grassenv = core.gisenv()
|
|
|
raise_on_error = False
|
|
|
|
|
|
+ # Set the global variable for faster access
|
|
|
+ current_mapset = grassenv["MAPSET"]
|
|
|
+ current_location = grassenv["LOCATION_NAME"]
|
|
|
+ current_gisdbase = grassenv["GISDBASE"]
|
|
|
+
|
|
|
# Check the g.gisenv variable TGIS_RAISE_ON_ERROR
|
|
|
if grassenv.has_key("TGIS_RAISE_ON_ERROR"):
|
|
|
if grassenv["TGIS_RAISE_ON_ERROR"] == "True" or grassenv["TGIS_RAISE_ON_ERROR"] == "1":
|
|
|
raise_on_error = True
|
|
|
-
|
|
|
- # Set the global variable current_mapset for fast mapset access
|
|
|
- _set_current_mapset(grassenv["MAPSET"])
|
|
|
+
|
|
|
# Start the GRASS message interface server
|
|
|
_init_tgis_message_interface(raise_on_error)
|
|
|
# Start the C-library interface server
|
|
|
_init_tgis_c_library_interface()
|
|
|
-
|
|
|
msgr = get_tgis_message_interface()
|
|
|
msgr.debug(1, "Inititate the temporal database")
|
|
|
-
|
|
|
+
|
|
|
if raise_on_error is True:
|
|
|
msgr.warning("TGIS_RAISE_ON_ERROR is True")
|
|
|
|
|
@@ -414,15 +445,33 @@ def init():
|
|
|
else:
|
|
|
# Set the default sqlite3 connection in case nothing was defined
|
|
|
core.run_command("t.connect", flags="d")
|
|
|
+ kv = core.parse_command("t.connect", flags="pg")
|
|
|
+ tgis_backend = kv["driver"]
|
|
|
|
|
|
+ # Database string from t.connect -pg
|
|
|
+ tgis_database = kv["database"]
|
|
|
+ # Set the parameter style
|
|
|
+ tgis_dbmi_paramstyle = dbmi.paramstyle
|
|
|
+
|
|
|
+ # Create the temporal database string
|
|
|
+ if tgis_backend == "sqlite":
|
|
|
+ # We substitute GRASS variables if they are located in the database string
|
|
|
+ # This behavior is in conjunction with db.connect
|
|
|
+ tgis_database_string = tgis_database
|
|
|
+ tgis_database_string = tgis_database_string.replace("$GISDBASE", current_gisdbase)
|
|
|
+ tgis_database_string = tgis_database_string.replace("$LOCATION_NAME", current_location)
|
|
|
+ tgis_database_string = tgis_database_string.replace("$MAPSET", current_mapset)
|
|
|
+ elif tgis_backend == "pg":
|
|
|
+ tgis_database_string = tgis_database
|
|
|
+
|
|
|
+ # We do not know if the database already exists
|
|
|
db_exists = False
|
|
|
- database = get_temporal_dbmi_init_string(kv=kv, grassenv=grassenv)
|
|
|
dbif = SQLDatabaseInterfaceConnection()
|
|
|
|
|
|
# Check if the database already exists
|
|
|
if tgis_backend == "sqlite":
|
|
|
# Check path of the sqlite database
|
|
|
- if os.path.exists(database):
|
|
|
+ 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';")
|
|
@@ -441,7 +490,6 @@ def init():
|
|
|
db_exists = True
|
|
|
|
|
|
if db_exists == True:
|
|
|
-
|
|
|
# Check the version of the temporal database
|
|
|
# This version works only with database of version 2
|
|
|
dbif.close()
|
|
@@ -450,7 +498,7 @@ def init():
|
|
|
dbif.close()
|
|
|
if metadata is None:
|
|
|
msgr.fatal(_("Unable to receiving temporal database metadata. Your temporal database is not supported."))
|
|
|
-
|
|
|
+
|
|
|
for entry in metadata:
|
|
|
if "tgis_version" in entry and entry[1] != str(get_tgis_version()):
|
|
|
msgr.fatal(_("Unsupported temporal database. Version mismatch.\n"
|
|
@@ -460,11 +508,11 @@ def init():
|
|
|
"Supported temporal database version is: %(tdb)i")%( {"tdb":get_tgis_db_version()}))
|
|
|
return
|
|
|
|
|
|
- create_temporal_database(dbif, database)
|
|
|
+ create_temporal_database(dbif)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
-def create_temporal_database(dbif, database):
|
|
|
+def create_temporal_database(dbif):
|
|
|
"""!This function will create the temporal database
|
|
|
|
|
|
It will create all tables and triggers that are needed to run
|
|
@@ -475,6 +523,7 @@ def create_temporal_database(dbif, database):
|
|
|
global tgis_backend
|
|
|
global tgis_version
|
|
|
global tgis_db_version
|
|
|
+ global tgis_database_string
|
|
|
|
|
|
template_path = get_sql_template_path()
|
|
|
msgr = get_tgis_message_interface()
|
|
@@ -528,11 +577,11 @@ def create_temporal_database(dbif, database):
|
|
|
stvds_tables_sql = stds_tables_template_sql.replace("STDS", "stvds")
|
|
|
str3ds_tables_sql = stds_tables_template_sql.replace("STDS", "str3ds")
|
|
|
|
|
|
- msgr.message(_("Create temporal database: %s" % (database)))
|
|
|
+ msgr.message(_("Create temporal database: %s" % (tgis_database_string)))
|
|
|
|
|
|
if tgis_backend == "sqlite":
|
|
|
# We need to create the sqlite3 database path if it does not exists
|
|
|
- tgis_dir = os.path.dirname(database)
|
|
|
+ tgis_dir = os.path.dirname(tgis_database_string)
|
|
|
if not os.path.exists(tgis_dir):
|
|
|
os.makedirs(tgis_dir)
|
|
|
# Set up the trigger that takes care of
|
|
@@ -633,6 +682,11 @@ class SQLDatabaseInterfaceConnection():
|
|
|
self.dbmi = psycopg2
|
|
|
|
|
|
self.msgr = get_tgis_message_interface()
|
|
|
+ self.msgr.debug(1, "SQLDatabaseInterfaceConnection constructor")
|
|
|
+
|
|
|
+ def __del__(self):
|
|
|
+ if self.connected is True:
|
|
|
+ self.close()
|
|
|
|
|
|
def rollback(self):
|
|
|
"""
|
|
@@ -650,9 +704,10 @@ class SQLDatabaseInterfaceConnection():
|
|
|
|
|
|
Supported backends are sqlite3 and postgresql
|
|
|
"""
|
|
|
- self.database = get_temporal_dbmi_init_string()
|
|
|
+ global tgis_database_string
|
|
|
+
|
|
|
if self.dbmi.__name__ == "sqlite3":
|
|
|
- self.connection = self.dbmi.connect(self.database,
|
|
|
+ self.connection = self.dbmi.connect(tgis_database_string,
|
|
|
detect_types = self.dbmi.PARSE_DECLTYPES | self.dbmi.PARSE_COLNAMES)
|
|
|
self.connection.row_factory = self.dbmi.Row
|
|
|
self.connection.isolation_level = None
|
|
@@ -660,7 +715,7 @@ class SQLDatabaseInterfaceConnection():
|
|
|
self.cursor.execute("PRAGMA synchronous = OFF")
|
|
|
self.cursor.execute("PRAGMA journal_mode = MEMORY")
|
|
|
elif self.dbmi.__name__ == "psycopg2":
|
|
|
- self.connection = self.dbmi.connect(self.database)
|
|
|
+ self.connection = self.dbmi.connect(tgis_database_string)
|
|
|
#self.connection.set_isolation_level(dbmi.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
|
|
self.cursor = self.connection.cursor(
|
|
|
cursor_factory = self.dbmi.extras.DictCursor)
|
|
@@ -668,7 +723,6 @@ class SQLDatabaseInterfaceConnection():
|
|
|
|
|
|
def close(self):
|
|
|
"""!Close the DBMI connection"""
|
|
|
- #print "Close connection to", self.database
|
|
|
self.connection.commit()
|
|
|
self.cursor.close()
|
|
|
self.connected = False
|
|
@@ -819,7 +873,10 @@ class SQLDatabaseInterfaceConnection():
|
|
|
|
|
|
def init_dbif(dbif):
|
|
|
"""!This method checks if the database interface connection exists,
|
|
|
- if not a new one will be created, connected and True will be returned
|
|
|
+ if not a new one will be created, connected and True will be returned.
|
|
|
+ If the database interface exists but is connected, the connection will be established.
|
|
|
+
|
|
|
+ @return the tuple (dbif, True|False)
|
|
|
|
|
|
Usage code sample:
|
|
|
@code
|
|
@@ -839,6 +896,9 @@ def init_dbif(dbif):
|
|
|
dbif = SQLDatabaseInterfaceConnection()
|
|
|
dbif.connect()
|
|
|
return dbif, True
|
|
|
+ elif dbif.connected is False:
|
|
|
+ dbif.connect()
|
|
|
+ return dbif, True
|
|
|
|
|
|
return dbif, False
|
|
|
|