#!/bin/sh
#
# BAREOS® - Backup Archiving REcovery Open Sourced
#
# Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
# Copyright (C) 2013-2020 Bareos GmbH & Co. KG
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of version three of the GNU Affero General Public
# License as published by the Free Software Foundation and included
# in the file LICENSE.
#
# 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
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# This script will update a BAREOS database to the latest version.
#

#
# Source the Bareos config functions.
#
. /usr/pkg/lib/bareos/scripts/bareos-config-lib.sh

db_name="${db_name:-`get_database_name bareos`}"
db_user="${db_user:-`get_database_user bareos`}"
db_version=`get_database_version`
bareos_sql_ddl=`get_database_ddl_dir`
temp_sql_schema="/tmp/tables.sql.$$"
default_db_type=`get_database_driver_default`
working_dir=`get_working_dir`

SHOW_WARNING="yes"

if [ "$1" = "-f" ]; then
   FORCE="yes"
   shift || true
fi

#
# See if the first argument is a valid backend name.
# If so the user overrides the default database backend.
#
if [ $# -gt 0 ]; then
   case $1 in
      sqlite3)
         db_type=$1
         shift
         ;;
      mysql)
         db_type=$1
         shift
         ;;
      postgresql)
         db_type=$1
         shift
         ;;
      *)
         ;;
   esac
fi

#
# If no new db_type is gives use the default db_type.
#
if [ -z "${db_type}" ]; then
   db_type="${default_db_type}"
fi

echo "Updating ${db_type} tables"

bindir=`get_database_utility_path ${db_type}`
if [ ! -z "${bindir}" ]; then
   PATH="$bindir:$PATH"
fi

while [ 1 ]
do
   #
   # Figure out what the current version of the database is.
   #
   case ${db_type} in
      sqlite3)
         DBVERSION=`echo 'SELECT MAX(VersionId) FROM Version;' | sqlite3 ${working_dir}/${db_name}.db`
         ;;
      mysql)
         DBVERSION=`mysql -D ${db_name} $* -e "SELECT MAX(VersionId) FROM Version\G" | \
                    sed -n -e 's/^.*VersionId.*: \(.*\)$/\1/p'`
         ;;
      postgresql)
         DBVERSION=`PGOPTIONS='--client-min-messages=warning' psql -d ${db_name} -t --pset format=unaligned -c "SELECT MAX(VersionId) FROM Version;" $*`
         ;;
      *)
         echo "Unknown database type ${db_type}"
         exit 1
         ;;
   esac

   if [ -z "${DBVERSION}" ]; then
      echo "Unable to determine version of Bareos ${db_type} database"
      exit 1
   fi

   if [ ${DBVERSION} = ${db_version} ]; then
      echo "Finished upgrading database to version ${db_version}"
      exit 0
   fi

   #
   # See if its a known conversion.
   #
   found=0
   known_conversions=`ls ${bareos_sql_ddl}/updates/${db_type}* 2>/dev/null| \
                      sed -e 's#.*/##' | \
                      cut -d'.' -f2`
   for conversion in ${known_conversions}; do
      start_version=`echo ${conversion} | cut -d_ -f1`
      end_version=`echo ${conversion} | cut -d_ -f2`

      if [ ${start_version} = ${DBVERSION} ]; then
         found=1
         break
      fi
   done

   if [ ${found} = 0 ]; then
      echo "Don't know how to upgrade from version ${DBVERSION} to ${db_version}"
      exit 1
   fi

   if [ "${SHOW_WARNING}" = "yes" -a ${DBVERSION} -lt 2171 ]; then
      echo "WARNING:"
      echo "  Updating the database to schema version 2171 will increase the required disk space."
      echo "  Especially it will require around twice the amount of disk space, during the migration."
      if [ "$FORCE" != "yes" ]; then
         echo "  Please verify you got enough disk space available and confirm by pressing <ENTER>."
         read input
         # warning already shown and confirmed. No need to show it again.
         SHOW_WARNING="no"
      fi
   fi

   sql_definitions="${bareos_sql_ddl}/updates/${db_type}.${conversion}.sql"
   if [ ! -f ${sql_definitions} ]; then
      echo "Unable to open database update definitions in file ${sql_definitions}"
      exit 1
   fi

   sed -e "s/@DB_NAME@/${db_name}/" \
       -e "s/@DB_USER@/${db_user}/" \
       ${sql_definitions} > ${temp_sql_schema}

   echo "Upgrading database schema from version ${start_version} to ${end_version}"

   case ${db_type} in
      sqlite3)
         sqlite3 $* ${working_dir}/${db_name}.db < ${temp_sql_schema}
         retval=$?
         ;;
      mysql)
         mysql -D ${db_name} $* < ${temp_sql_schema}
         retval=$?
         ;;
      postgresql)
         PGOPTIONS='--client-min-messages=warning' psql -f ${temp_sql_schema} -d ${db_name} $*
         retval=$?
         if [ $retval -eq 0 ] && [ ${end_version} -eq 2192 ]; then
             PGSQLVERSION=`PGOPTIONS='--client-min-messages=warning' psql -d template1 -c 'SELECT version()' $* 2>/dev/null | \
                    awk '/PostgreSQL/ { print $2 }' | \
                    cut -d '.' -f 1,2`
             case ${PGSQLVERSION} in
                 10.*|11.*|12.*)
                     PGOPTIONS='--client-min-messages=warning' psql -d ${db_name} -c 'ALTER SEQUENCE basefiles_baseid_seq AS BIGINT'
                     result=$?
                     if [ $result -ne 0 ]; then
                         echo "WARNING: Failed to update sequence basefiles_baseid_seq"
                     fi
                     ;;
             esac
         fi
         ;;
   esac

   rm -f ${temp_sql_schema}

   if [ ${retval} != 0 ]; then
      echo "Failed to upgrade database schema from version ${start_version} to ${end_version}"
      exit ${retval}
   fi
done

exit ${retval}
