#!/bin/sh
#
# Copyright (C) 1994-2021 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
}

upgrade_pbs_schema_from_v1_4_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 DROP COLUMN ji_numattr;
		ALTER TABLE pbs.job DROP COLUMN ji_ordering;
		ALTER TABLE pbs.job DROP COLUMN ji_priority;
		ALTER TABLE pbs.job DROP COLUMN ji_endtbdry;
		ALTER TABLE pbs.job DROP COLUMN ji_momaddr;
		ALTER TABLE pbs.job DROP COLUMN ji_momport;
		ALTER TABLE pbs.job RENAME COLUMN ji_4jid to ji_jid;
		ALTER TABLE pbs.job ALTER COLUMN ji_qrank TYPE BIGINT;
		ALTER TABLE pbs.job DROP COLUMN ji_4ash;
		ALTER TABLE pbs.resv DROP COLUMN ri_type;
		ALTER TABLE pbs.resv DROP COLUMN ri_numattr;
		ALTER TABLE pbs.resv DROP COLUMN ri_resvTag;
		ALTER TABLE pbs.resv DROP COLUMN ri_un_type;
		ALTER TABLE pbs.resv DROP COLUMN ri_fromsock;
		ALTER TABLE pbs.resv DROP COLUMN ri_fromaddr;
		ALTER TABLE pbs.server DROP COLUMN sv_numjobs;
		ALTER TABLE pbs.server DROP COLUMN sv_numque;
		ALTER TABLE pbs.server DROP COLUMN sv_svraddr;
		ALTER TABLE pbs.server DROP COLUMN sv_svrport;
		ALTER TABLE pbs.queue RENAME COLUMN qu_ctime to qu_creattm;
		ALTER TABLE pbs.queue RENAME COLUMN qu_mtime to qu_savetm;
		UPDATE pbs.info SET pbs_schema_version = '1.5.0';
	EOF
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "Error deleting ri_type during upgrade"
		echo "Please check dataservice logs"
		return $ret
	fi
}

# start of the upgrade schema script
. ${PBS_EXEC}/libexec/pbs_db_env
tmpdir=${PBS_TMPDIR:-${TMPDIR:-"/var/tmp"}}
PBS_CURRENT_SCHEMA_VER='1.5.0'

#
# 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
	return 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"
fi

if [ "$ver" = "1.4.0" ]; then
	upgrade_pbs_schema_from_v1_4_0
	ret=$?
	if [ $ret -ne 0 ]; then
		exit $ret
	fi
	ver="1.5.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
