Browse Source

t.downgrade: downgrade a temporal db from version 3 to 2 (#1449)

* Downgrade a temporal db from version 3 to 2

* Apply suggestions from code review

Co-authored-by: Markus Neteler <neteler@gmail.com>
Markus Metz 4 years ago
parent
commit
ab4c960306

+ 99 - 2
lib/python/temporal/core.py

@@ -475,7 +475,7 @@ def get_available_temporal_mapsets():
 ###############################################################################
 
 
-def init(raise_fatal_error=False):
+def init(raise_fatal_error=False, skip_db_version_check=False):
     """This function set the correct database backend from GRASS environmental
        variables and creates the grass temporal database structure for raster,
        vector and raster3d maps as well as for the space-time datasets strds,
@@ -516,6 +516,10 @@ def init(raise_fatal_error=False):
                                   exception will be raised in case a fatal
                                   error occurs in the init process, otherwise
                                   sys.exit(1) will be called.
+     :param skip_db_version_check: Set this True to skip mismatch temporal
+                                   database version check.
+                                   Recommended to be used only for
+                                   downgrade_temporal_database().
     """
     # 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
@@ -663,8 +667,11 @@ def init(raise_fatal_error=False):
                    " created automatically.\n"
 
     if db_exists is True:
-        # Check the version of the temporal database
         dbif.close()
+        if skip_db_version_check is True:
+            return
+
+        # Check the version of the temporal database
         dbif.connect()
         metadata = get_tgis_metadata(dbif)
         dbif.close()
@@ -705,6 +712,29 @@ def get_database_info_string():
 ###############################################################################
 
 
+def _create_temporal_database_views(dbif):
+    """Create all views in the temporal database (internal use only)
+
+    Used by downgrade_temporal_database().
+
+    :param dbif: The database interface to be used
+    """
+    template_path = get_sql_template_path()
+
+    for sql_filename in (
+        "raster_views",
+        "raster3d_views",
+        "vector_views",
+        "strds_views",
+        "str3ds_views",
+        "stvds_views",
+    ):
+        sql_filepath = open(
+            os.path.join(template_path, sql_filename + ".sql"), "r"
+        ).read()
+        dbif.execute_transaction(sql_filepath)
+
+
 def create_temporal_database(dbif):
     """This function will create the temporal database
 
@@ -844,6 +874,73 @@ def create_temporal_database(dbif):
 ###############################################################################
 
 
+def downgrade_temporal_database(dbif):
+    """This function will downgrade the temporal database if needed.
+
+    It will downdate all tables and triggers that are requested by
+    currently supported TGIS DB version.
+
+    :param dbif: The database interface to be used
+    """
+    global tgis_database_string
+    global tgis_db_version
+
+    metadata = get_tgis_metadata(dbif)
+
+    msgr = get_tgis_message_interface()
+    if metadata is None:
+        msgr.fatal(
+            _(
+                "Unable to receive temporal database metadata.\n"
+                "Current temporal database info:%(info)s"
+            )
+            % ({"info": get_database_info_string()})
+        )
+    downgrade_db_from = None
+    for entry in metadata:
+        if "tgis_db_version" in entry and entry[1] != str(tgis_db_version):
+            downgrade_db_from = entry[1]
+            break
+
+    if downgrade_db_from is None:
+        msgr.message(_("Temporal database is up-to-date. Operation canceled"))
+        dbif.close()
+        return
+
+    template_path = get_sql_template_path()
+    try:
+        downgrade_db_sql = open(
+            os.path.join(
+                template_path,
+                "downgrade_db_%s_to_%s.sql" % (downgrade_db_from, tgis_db_version),
+            ),
+            "r",
+        ).read()
+    except FileNotFoundError:
+        msgr.fatal(
+            _("Unsupported TGIS DB downgrade scenario: from version %s to %s")
+            % (downgrade_db_from, tgis_db_version)
+        )
+
+    drop_views_sql = open(os.path.join(template_path, "drop_views.sql"), "r").read()
+
+    msgr.message(
+        _("Downgrading temporal database <%s> from version %s to %s...")
+        % (tgis_database_string, downgrade_db_from, tgis_db_version)
+    )
+    # Drop views
+    dbif.execute_transaction(drop_views_sql)
+    # Perform upgrade
+    dbif.execute_transaction(downgrade_db_sql)
+    # Recreate views
+    _create_temporal_database_views(dbif)
+
+    dbif.close()
+
+
+###############################################################################
+
+
 def _create_tgis_metadata_table(content, dbif=None):
     """!Create the temporal gis metadata table which stores all metadata
        information about the temporal database.

+ 83 - 0
lib/temporal/SQL/downgrade_db_3_to_2.sql

@@ -0,0 +1,83 @@
+--#############################################################################
+-- This SQL script downgrades TGIS DB from version 3 to version 2.
+--
+-- Author: Markus Metz
+--#############################################################################
+
+-- raster_metadata_table.sql
+CREATE TEMPORARY TABLE raster_metadata_backup(
+  id VARCHAR NOT NULL,               -- The id (PFK) is the unique identifier for all tables, it is based on name and mapset (name@mapset) and is used as primary key
+  datatype VARCHAR NOT NULL,
+  cols INTEGER NOT NULL,
+  rows INTEGER NOT NULL,
+  number_of_cells INTEGER NOT NULL,
+  nsres DOUBLE PRECISION NOT NULL,
+  ewres DOUBLE PRECISION NOT NULL,
+  min DOUBLE PRECISION,
+  max DOUBLE PRECISION,
+  PRIMARY KEY (id)
+);
+INSERT INTO raster_metadata_backup SELECT id,datatype,cols,rows,number_of_cells,nsres,ewres,min,max FROM raster_metadata;
+DROP TABLE raster_metadata;
+CREATE TABLE raster_metadata(
+  id VARCHAR NOT NULL,               -- The id (PFK) is the unique identifier for all tables, it is based on name and mapset (name@mapset) and is used as primary key
+  datatype VARCHAR NOT NULL,
+  cols INTEGER NOT NULL,
+  rows INTEGER NOT NULL,
+  number_of_cells INTEGER NOT NULL,
+  nsres DOUBLE PRECISION NOT NULL,
+  ewres DOUBLE PRECISION NOT NULL,
+  min DOUBLE PRECISION,
+  max DOUBLE PRECISION,
+  PRIMARY KEY (id)
+);
+INSERT INTO raster_metadata SELECT id,datatype,cols,rows,number_of_cells,nsres,ewres,min,max FROM raster_metadata_backup;
+DROP TABLE raster_metadata_backup;
+
+
+-- strds_metadata_table.sql
+CREATE TEMPORARY TABLE strds_metadata_backup(
+  id VARCHAR NOT NULL,          -- Id of the space-time dataset, this is the primary key
+  raster_register VARCHAR,      -- The id of the table in which the raster maps are registered for this dataset
+  number_of_maps INTEGER,       -- The number of registered raster maps
+  max_min DOUBLE PRECISION,     -- The minimal maximum of the registered raster maps
+  min_min DOUBLE PRECISION,     -- The minimal minimum of the registered raster maps
+  max_max DOUBLE PRECISION,     -- The maximal maximum of the registered raster maps
+  min_max DOUBLE PRECISION,     -- The maximal minimum of the registered raster maps
+  nsres_min DOUBLE PRECISION,   -- The lowest north-south resolution of the registered raster maps
+  nsres_max DOUBLE PRECISION,   -- The highest north-south resolution of the registered raster maps
+  ewres_min DOUBLE PRECISION,   -- The lowest east-west resolution of the registered raster maps
+  ewres_max DOUBLE PRECISION,   -- The highest east-west resolution of the registered raster maps
+  aggregation_type VARCHAR,     -- The aggregation type of the dataset (mean, min, max, ...) set by aggregation modules
+  title VARCHAR,                -- Title of the space-time raster dataset
+  description VARCHAR,          -- Detailed description of the space-time raster dataset
+  command VARCHAR,              -- The command that was used to create the space time raster dataset
+  PRIMARY KEY (id)
+);
+INSERT INTO strds_metadata_backup SELECT id,raster_register,number_of_maps,max_min,min_min,max_max,min_max,nsres_min,nsres_max,ewres_min,ewres_max,aggregation_type,title,description,command FROM strds_metadata;
+DROP TABLE strds_metadata;
+CREATE TABLE strds_metadata(
+  id VARCHAR NOT NULL,          -- Id of the space-time dataset, this is the primary key
+  raster_register VARCHAR,      -- The id of the table in which the raster maps are registered for this dataset
+  number_of_maps INTEGER,       -- The number of registered raster maps
+  max_min DOUBLE PRECISION,     -- The minimal maximum of the registered raster maps
+  min_min DOUBLE PRECISION,     -- The minimal minimum of the registered raster maps
+  max_max DOUBLE PRECISION,     -- The maximal maximum of the registered raster maps
+  min_max DOUBLE PRECISION,     -- The maximal minimum of the registered raster maps
+  nsres_min DOUBLE PRECISION,   -- The lowest north-south resolution of the registered raster maps
+  nsres_max DOUBLE PRECISION,   -- The highest north-south resolution of the registered raster maps
+  ewres_min DOUBLE PRECISION,   -- The lowest east-west resolution of the registered raster maps
+  ewres_max DOUBLE PRECISION,   -- The highest east-west resolution of the registered raster maps
+  aggregation_type VARCHAR,     -- The aggregation type of the dataset (mean, min, max, ...) set by aggregation modules
+  title VARCHAR,                -- Title of the space-time raster dataset
+  description VARCHAR,          -- Detailed description of the space-time raster dataset
+  command VARCHAR,              -- The command that was used to create the space time raster dataset
+  PRIMARY KEY (id)
+);
+INSERT INTO strds_metadata SELECT id,raster_register,number_of_maps,max_min,min_min,max_max,min_max,nsres_min,nsres_max,ewres_min,ewres_max,aggregation_type,title,description,command FROM strds_metadata_backup;
+DROP TABLE strds_metadata_backup;
+
+-- tgis_metadata
+UPDATE tgis_metadata
+  SET value = '2'
+  WHERE key = 'tgis_db_version';

+ 29 - 0
lib/temporal/SQL/drop_views.sql

@@ -0,0 +1,29 @@
+--#############################################################################
+-- This SQL script drops all existing vies (used by upgrade_temporal_database())
+--
+-- Author: Martin Landa landa.martin <at> gmail <dot> com
+--#############################################################################
+
+-- raster_views
+DROP VIEW raster_view_abs_time;
+DROP VIEW raster_view_rel_time;
+
+-- raster3d_views
+DROP VIEW raster3d_view_abs_time;
+DROP VIEW raster3d_view_rel_time;
+
+-- vector_views
+DROP VIEW vector_view_abs_time;
+DROP VIEW vector_view_rel_time;
+
+-- strds_views
+DROP VIEW strds_view_abs_time;
+DROP VIEW strds_view_rel_time;
+
+-- str3ds_views
+DROP VIEW str3ds_view_abs_time;
+DROP VIEW str3ds_view_rel_time;
+
+-- stvds_views
+DROP VIEW stvds_view_abs_time;
+DROP VIEW stvds_view_rel_time;

+ 1 - 0
temporal/Makefile

@@ -3,6 +3,7 @@ MODULE_TOPDIR = ..
 SUBDIRS = \
 	t.connect \
 	t.create \
+	t.downgrade \
 	t.support \
 	t.topology \
 	t.list \

+ 7 - 0
temporal/t.downgrade/Makefile

@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../../
+
+PGM = t.downgrade
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script $(TEST_DST)

+ 28 - 0
temporal/t.downgrade/t.downgrade.html

@@ -0,0 +1,28 @@
+<h2>DESCRIPTION</h2>
+
+This module downgrades the TGIS DB version.
+
+At time it only downgrades TGIS DB from version 3 (after introducing band
+reference support ("image collections"), see
+<a href="https://github.com/OSGeo/grass/pull/63">PR #63</a>) to version 3
+(with band reference support).
+
+<h2>EXAMPLE</h2>
+
+<div class="code"><pre>
+t.downgrade
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="https://grass.osgeo.org/grass-stable/manuals/t.info.html">t.info</a>
+</em>
+
+<h2>AUTHORS</h2>
+
+Martin Landa, Markus Neteler, Markus Metz
+
+<!--
+<p><i>Last changed: $Date$</i>
+-->

+ 47 - 0
temporal/t.downgrade/t.downgrade.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+############################################################################
+#
+# MODULE:       t.downgrade
+# AUTHOR(S):    Martin Landa, Markus Neteler, Markus Metz
+# PURPOSE:      Downgrade of TGRASS DB
+# COPYRIGHT:    (C) 2019-2021 by Martin Landa, and the GRASS Development Team
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+############################################################################
+
+#%module
+#% description: Downgrades the version of a space time dataset (TGRASS DB).
+#% keyword: temporal
+#% keyword: metadata
+#% keyword: time
+#%end
+
+import grass.script as gs
+
+
+def main():
+    # lazy imports
+    import grass.temporal as tgis
+
+    tgis.init(skip_db_version_check=True)
+
+    dbif = tgis.SQLDatabaseInterfaceConnection()
+    dbif.connect()
+
+    tgis.downgrade_temporal_database(dbif)
+
+    return 0
+
+if __name__ == "__main__":
+    gs.parser()
+    main()