#!/bin/sh
#
# Copyright (C) 1994-2020 Altair Engineering, Inc.
# For more information, contact Altair at www.altair.com.
#
# This file is part of both the OpenPBS software ("OpenPBS")
# and the PBS Professional ("PBS Pro") software.
#
# Open Source License Information:
#
# OpenPBS is free software. You can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# OpenPBS 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, see <http://www.gnu.org/licenses/>.
#
# Commercial License Information:
#
# PBS Pro is commercially licensed software that shares a common core with
# the OpenPBS software.  For a copy of the commercial license terms and
# conditions, go to: (http://www.pbspro.com/agreement.html) or contact the
# Altair Legal Department.
#
# Altair's dual-license business model allows companies, individuals, and
# organizations to create proprietary derivative works of OpenPBS and
# distribute them - whether embedded or bundled with other software -
# under a commercial license agreement.
#
# Use of Altair's trademarks, including but not limited to "PBS™",
# "OpenPBS®", "PBS Professional®", and "PBS Pro™" and Altair's logos is
# subject to Altair's trademark licensing policies.



upgrade_pbs_schema_from_v1_0_0() {

	${PGSQL_DIR}/bin/psql -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} <<-EOF > /dev/null
		alter table pbs.node alter column nd_index drop default;
		alter table pbs.node drop constraint node_nd_index_key;
		create index job_scr_idx on pbs.job_scr (ji_jobid);
		drop sequence pbs.node_sequence;

		\set PBS_MAXHOSTNAME	'64'
		create sequence pbs.svr_id_seq;
		alter table pbs.server add column sv_hostname varchar(:PBS_MAXHOSTNAME);
		update pbs.server set sv_hostname = sv_name;
		alter table pbs.server alter column sv_hostname set not null;
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Some datastore transformations failed to complete"
		echo "Please check dataservice logs"
		return $ret
	fi

	${PBS_EXEC}/sbin/pbs_server -t updatedb > /dev/null
	ret=$?
	if [ $ret -ne 0 -o -f ${PBS_HOME}/server_priv/serverdb ] ; then
		echo "*** Error during overlay upgrade"
		return $ret
	fi
}

upgrade_pbs_schema_from_v1_1_0() {

	${PGSQL_DIR}/bin/psql -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} <<-EOF > /dev/null
		ALTER TABLE pbs.info ALTER COLUMN pbs_schema_version TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_jobid TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_sv_name TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_queue TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_destin TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_4jid TYPE text;
		ALTER TABLE pbs.job ALTER COLUMN ji_4ash TYPE text;
		ALTER TABLE pbs.job_attr ALTER COLUMN ji_jobid TYPE text;
		ALTER TABLE pbs.job_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.job_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.job_scr ALTER COLUMN ji_jobid TYPE text;
		ALTER TABLE pbs.node ALTER COLUMN nd_name TYPE text;
		ALTER TABLE pbs.node ALTER COLUMN nd_hostname TYPE text;
		ALTER TABLE pbs.node ALTER COLUMN nd_pque TYPE text;
		ALTER TABLE pbs.node_attr ALTER COLUMN nd_name TYPE text;
		ALTER TABLE pbs.node_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.node_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.queue ALTER COLUMN qu_name TYPE text;
		ALTER TABLE pbs.queue ALTER COLUMN qu_sv_name TYPE text;
		ALTER TABLE pbs.queue_attr ALTER COLUMN qu_name TYPE text;
		ALTER TABLE pbs.queue_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.queue_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.resv ALTER COLUMN ri_resvid TYPE text;
		ALTER TABLE pbs.resv ALTER COLUMN ri_sv_name TYPE text;
		ALTER TABLE pbs.resv ALTER COLUMN ri_queue TYPE text;
		ALTER TABLE pbs.resv_attr ALTER COLUMN ri_resvid TYPE text;
		ALTER TABLE pbs.resv_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.resv_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.scheduler ALTER COLUMN sched_name TYPE text;
		ALTER TABLE pbs.scheduler ALTER COLUMN sched_sv_name TYPE text;
		ALTER TABLE pbs.scheduler_attr ALTER COLUMN sched_name TYPE text;
		ALTER TABLE pbs.scheduler_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.scheduler_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.server ALTER COLUMN sv_name TYPE text;
		ALTER TABLE pbs.server ALTER COLUMN sv_hostname TYPE text;
		ALTER TABLE pbs.server_attr ALTER COLUMN sv_name TYPE text;
		ALTER TABLE pbs.server_attr ALTER COLUMN attr_name TYPE text;
		ALTER TABLE pbs.server_attr ALTER COLUMN attr_resource TYPE text;
		ALTER TABLE pbs.subjob_track ALTER COLUMN ji_jobid TYPE text;
		alter table pbs.job drop constraint job_pkey cascade;
		create index ji_jobid_idx on pbs.job (ji_jobid);
		drop index pbs.job_attr_idx;
		create index job_attr_idx on pbs.job_attr (ji_jobid, attr_name, attr_resource);
		alter table pbs.subjob_track drop constraint subjob_track_pkey cascade;
		create index subjob_jid_idx on pbs.subjob_track (ji_jobid, trk_index);
		update pbs.info set pbs_schema_version = '1.2.0';
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Some datastore transformations failed to complete"
		echo "Please check dataservice logs"
		return $ret
	fi
}

upgrade_pbs_schema_from_v1_2_0() {

	${PGSQL_DIR}/bin/psql -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} <<-EOF > /dev/null
		DROP TABLE pbs.subjob_track;
		INSERT INTO pbs.scheduler (sched_name, sched_sv_name, sched_savetm, sched_creattm) VALUES ('default', '1', localtimestamp, localtimestamp);
		ALTER TABLE pbs.scheduler_attr DROP CONSTRAINT scheduler_attr_fk;
		UPDATE pbs.scheduler_attr SET sched_name='default' WHERE sched_name='1';
		ALTER TABLE pbs.scheduler_attr ADD CONSTRAINT scheduler_attr_fk
			FOREIGN KEY (sched_name)
			REFERENCES pbs.scheduler (sched_name)
			ON DELETE CASCADE
			ON UPDATE NO ACTION
			NOT DEFERRABLE;
		DELETE FROM pbs.scheduler WHERE sched_name='1';
		UPDATE pbs.info SET pbs_schema_version = '1.3.0';
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Some datastore transformations failed to complete"
		echo "Please check dataservice logs"
		return $ret
	fi
}

upgrade_pbs_schema_from_v1_3_0() {

	${PGSQL_DIR}/bin/psql -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} <<-EOF > /dev/null
		ALTER TABLE pbs.job ADD CONSTRAINT jobid_pk PRIMARY KEY (ji_jobid);
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Primary key violation"
		echo "Please check dataservice logs"
		return $ret
	fi

	${PGSQL_DIR}/bin/psql -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} <<-EOF > /dev/null

		CREATE EXTENSION hstore SCHEMA public;

		ALTER TABLE pbs.job ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.job SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.job_attr WHERE pbs.job_attr.ji_jobid=pbs.job.ji_jobid) AS attr);
		UPDATE pbs.job SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.job ALTER COLUMN attributes SET NOT NULL;

		ALTER TABLE pbs.node ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.node SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.node_attr WHERE pbs.node_attr.nd_name=pbs.node.nd_name) AS attr);
		UPDATE pbs.node SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.node ALTER COLUMN attributes SET NOT NULL;

		ALTER TABLE pbs.queue ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.queue SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.queue_attr WHERE pbs.queue_attr.qu_name=pbs.queue.qu_name) AS attr);
		UPDATE pbs.queue SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.queue ALTER COLUMN attributes SET NOT NULL;

		ALTER TABLE pbs.resv ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.resv SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.resv_attr WHERE pbs.resv_attr.ri_resvid=pbs.resv.ri_resvid) AS attr);
		UPDATE pbs.resv SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.resv ALTER COLUMN attributes SET NOT NULL;

		ALTER TABLE pbs.scheduler ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.scheduler SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.scheduler_attr WHERE pbs.scheduler_attr.sched_name=pbs.scheduler.sched_name) AS attr);
		UPDATE pbs.scheduler SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.scheduler ALTER COLUMN attributes SET NOT NULL;

		ALTER TABLE pbs.server ADD attributes hstore DEFAULT ''::hstore;
		UPDATE pbs.server SET attributes=(
			SELECT hstore(array_agg(attr.key ), array_agg(attr.value))
				FROM ( SELECT concat(attr_name, '.' , attr_resource) AS key,
					      concat(attr_flags, '.' , attr_value) AS value
						FROM pbs.server_attr WHERE pbs.server_attr.sv_name=pbs.server.sv_name) AS attr);
		UPDATE pbs.server SET attributes='' WHERE attributes IS NULL;
		ALTER TABLE pbs.server ALTER COLUMN attributes SET NOT NULL;

		DROP TABLE pbs.server_attr;
		DROP TABLE pbs.scheduler_attr;
		DROP TABLE pbs.node_attr;
		DROP TABLE pbs.queue_attr;
		DROP TABLE pbs.resv_attr;
		DROP TABLE pbs.job_attr;
		DROP INDEX pbs.resv_idx_cr;
		DROP INDEX pbs.ji_jobid_idx;
		DROP sequence pbs.svr_id_seq;

		ALTER INDEX pbs.job_src_idx RENAME TO job_scr_idx;
		ALTER TABLE pbs.server ALTER COLUMN sv_jobidnumber TYPE BIGINT;
		ALTER TABLE pbs.scheduler DROP COLUMN sched_sv_name;
		ALTER TABLE pbs.queue DROP COLUMN qu_sv_name;
		ALTER TABLE pbs.resv DROP COLUMN ri_sv_name;
		ALTER TABLE pbs.job DROP COLUMN ji_sv_name;
		ALTER TABLE pbs.server
		DROP COLUMN sv_name,
		DROP COLUMN sv_hostname;

		UPDATE pbs.info SET pbs_schema_version = '1.4.0';
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Some datastore transformations failed to complete"
		echo "Please check dataservice logs"
		return $ret
	fi
}

# start of the upgrade schema script

tmpdir=${PBS_TMPDIR:-${TMPDIR:-"/var/tmp"}}
PBS_CURRENT_SCHEMA_VER='1.4.0'
conf=${PBS_CONF_FILE:-/etc/pbs.conf}
PBS_DATA_SERVICE_PORT="$1"
PBS_DATA_SERVICE_USER="$2"

. $conf
. "$PBS_EXEC"/libexec/pbs_pgsql_env.sh

#
# pbs_dataservice command now has more diagnostic output.
# It can tell why it could not start, for example, that
# dataservice might be running on another host.
# So capture pbs_dataservice output and display in case of
# errors during starting.
#
outfile="${tmpdir}/pbs_dataservice_output_$$"

${PBS_EXEC}/sbin/pbs_dataservice status > /dev/null
if [ $? -eq 0 ]; then
    # running stop now
    ${PBS_EXEC}/sbin/pbs_dataservice stop > /dev/null
    if [ $? -ne 0 ]; then
        echo "Failed to stop PBS Dataservice"
        exit 1
    fi
fi

ret=$?
if [ $ret -ne 0 ]; then
    exit $ret
fi

# restart with new credentials
# redirect the output, dont execute inside `` since
# postgres processes would otherwise cause the script
# to hang forever
#
${PBS_EXEC}/sbin/pbs_dataservice start > ${outfile}
if [ $? -ne 0 ]; then
    cat ${outfile}
    rm -f ${outfile}
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    exit 1
fi
rm -f ${outfile}

ver=`${PGSQL_DIR}/bin/psql -A -t -p ${PBS_DATA_SERVICE_PORT} -d pbs_datastore -U ${PBS_DATA_SERVICE_USER} -c "select pbs_schema_version from pbs.info"`
if [ "$ver" = "${PBS_CURRENT_SCHEMA_VER}" ]; then
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    exit 0
fi

if [ "$ver" = "1.0.0" ]; then
    upgrade_pbs_schema_from_v1_0_0
    ret=$?
    if [ $ret -ne 0 ]; then
        ret=$?
        if [ $ret -ne 0 ]; then
            exit $ret
        fi
        exit 1
    fi
    ver="1.1.0"
fi

${PBS_EXEC}/sbin/pbs_dataservice status > /dev/null
if [ $? -eq 1 ]; then
    # not running, start now
    ${PBS_EXEC}/sbin/pbs_dataservice start > ${outfile}
    if [ $? -ne 0 ]; then
        cat ${outfile}
        rm -f ${outfile}
        ret=$?
        if [ $ret -ne 0 ]; then
            exit $ret
        fi
        exit 1
    fi
    rm -f ${outfile}
fi

if [ "$ver" = "1.1.0" ]; then
    upgrade_pbs_schema_from_v1_1_0
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    ver="1.2.0"
fi

if [ "$ver" = "1.2.0" ]; then
    upgrade_pbs_schema_from_v1_2_0
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    ver="1.3.0"
fi

if [ "$ver" = "1.3.0" ]; then
    upgrade_pbs_schema_from_v1_3_0
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    ver="1.4.0"
else
    echo "Cannot upgrade PBS datastore version $ver"
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    exit 1
fi

${PBS_EXEC}/sbin/pbs_dataservice status > /dev/null
if [ $? -eq 1 ]; then
    # not running, start now
    ${PBS_EXEC}/sbin/pbs_dataservice start > ${outfile}
    if [ $? -ne 0 ]; then
        cat ${outfile}
        rm -f ${outfile}
        ret=$?
        if [ $ret -ne 0 ]; then
            exit $ret
        fi
        exit 1
    fi
fi
rm -f ${outfile}

${PBS_EXEC}/sbin/pbs_dataservice stop > /dev/null

ret=$?
exit $ret
