diff --git a/.gitignore b/.gitignore index 000d41ef..b54ed666 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -build*/ \ No newline at end of file +build*/ +!game/server/database/build/ \ No newline at end of file diff --git a/game/server/database/build/linux/database_update.pl b/game/server/database/build/linux/database_update.pl new file mode 100755 index 00000000..4e58deaa --- /dev/null +++ b/game/server/database/build/linux/database_update.pl @@ -0,0 +1,715 @@ +#!/usr/bin/perl + +# Script to create/initialze/update the database +# Update the database to the latest version by applying delta files + +use strict; +use Getopt::Long; + +&main; + +sub main +{ + + &GetOptions("delta","drop","create","toversion=s","fromversion=s","packages","noversioncheck","help","username:s","loginusername:s","goldusername:s","password:s","service:s","buildcluster","grantpermissions","grantgoldpermissions","configurelimits","addclusterforlogin","createnewcluster", "newschema", "dbausername:s","dbapassword:s","queries","execquery:s"); + + if ($::opt_help || !($::opt_drop || $::opt_create || $::opt_delta || $::opt_packages || $::opt_grantpermissions || $::opt_grantgoldpermissions || $::opt_configurelimits || $::opt_addclusterforlogin || $::opt_createnewcluster||$::opt_queries||$::opt_execquery)) + { + print "Usage: database_update.pl [COMMAND] [OPTION]... \n"; + print "Create a new database or update an existing database to the latest version.\n"; + print "\n"; + print "Commands:\n"; + print " --create Create a new database.\n"; + print " --delta Update the database by applying deltas\n"; + print " --drop Drop an existing database.\n"; + print " --packages Update the PL/SQL packages. (Done automatically by other options.)\n"; + print " --createnewcluster Do all the steps needed to create a new live cluster.\n"; + print " --grantpermissions Grant permissions on all the objects in the schema to public\n"; + print " --grantgoldpermissions Grant permissions on all the objects in the gold schema to public (useful after importing the gold schema).\n"; + print " --configurelimits Prompt for character and account limits stored in the login database,\n"; + print " e.g. number of users per cluster\n"; + print " --addclusterforlogin Add a cluster to the login database (will prompt for the name)\n"; + print " --help Display these options.\n"; + print "\n"; + print "Options:\n"; + print " --fromversion=VER Override checking the database and specify the\n"; + print " starting version instead.\n"; + print " --toversion=VER Specify the version to which to update the database.\n"; + print " (Default: latest version.)\n"; + print " --noversioncheck Don't check the version number after running each update script.\n"; + print " --username=NAME Specify the database user name. (Defaults to \$USER.)\n"; + print " --loginusername=NAME Specify the login database user name, required for --configurelimits and --addclusterforlogin\n"; + print " --goldusername=NAME Specify the gold database user name, required for --grantgoldpermissions\n"; + print " --password=PASSWORD Specify the database password. (Defaults to \"changeme\".)\n"; + print " --service=NAME Specify the database service name. (Defaults to \"swodb\".)\n"; + print " --buildcluster Use this option if you set usename = buildcluster\n"; + print " --newschema Add this option to auto create schema if it doesn't exist\n"; + print " --dbausername Must be used with newschema option\n"; + print " --dbapassword Must be used with newschema option\n"; + print " --queries Run one time queries from list in automated_queries table\n"; + print " --execquery Execute query\n"; + print "\n"; + + exit; + } + + if ($::opt_createnewcluster) + { + # this is equivalent to setting the following options individually + $::opt_create=1; + $::opt_grantpermissions=1; + $::opt_grantgoldpermissions=1; + $::opt_configurelimits=1; + $::opt_addclusterforlogin=1; + } + + #check for usernames that must be specified + if ($::opt_loginusername eq "" && ($::opt_configurelimits || $::opt_addclusterforlogin)) + { + die "The login database user name must be specified with --loginusername=NAME\n"; + } + if ($::opt_goldusername eq "" && ($::opt_grantgoldpermissions)) + { + die "The gold database user name must be specified with --goldusername=NAME\n"; + } + + &doDrop if ($::opt_drop); + &doCreate if ($::opt_create); + if ($::opt_delta) + { + $::didAnUpdate = &doDeltaUpdates($::opt_fromversion,$::opt_toversion,$::opt_noversioncheck); + } + + if ($::didAnUpdate || $::opt_packages) + { + &updatePackages; + } + + if ($::opt_grantpermissions) + { + &doGrantPermissions; + } + + if ($::opt_grantgoldpermissions) + { + &doGrantGoldPermissions; + } + + if ($::opt_configureforlogin) + { + &doConfigureForLogin; + } + + if ($::opt_configurelimits) + { + &doConfigureLimits; + } + + if ($::opt_addclusterforlogin) + { + &doAddClusterForLogin; + } + + if ($::opt_queries) + { + &doRunOneTimeQueries; + } + + if ($::opt_execquery) + { + &doExecQuery; + } + +exit 0; + +} + +sub doDrop +{ + system (&sqlplus." @../../queries/drop_all_objects.sql"); +} + +sub doCreate +{ + if ($::opt_toversion) + { + die "Cannot specify --toversion with --create\n"; + } + + if ($::opt_newschema) + { + my($user); + $user=$::opt_username; + $user=$ENV{"USER"} if ($user eq ""); + + my $pwd = $::opt_password; + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + + open (OUTFILE,"| ".&sqlplusForDBA." > /dev/null"); + print OUTFILE "CREATE USER $user PROFILE DEFAULT IDENTIFIED BY $pwd DEFAULT TABLESPACE DATA TEMPORARY TABLESPACE TEMP ACCOUNT UNLOCK;\n"; + print OUTFILE "GRANT CREATE TYPE TO $user;\n"; + print OUTFILE "GRANT UNLIMITED TABLESPACE TO $user;\n"; + print OUTFILE "GRANT SWG_GENERAL TO $user;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + } + + doCreatesInDirectory("../../shared_schema/"); + doCreatesInDirectory("../../schema/"); + doCreatesInDirectory("../../login_schema/"); + doCreatesInDirectory("../../sp_character_schema/"); + + &updatePackages; + + doDataSetupInDirectory("../../shared_data/"); + doDataSetupInDirectory("../../data/"); + doDataSetupInDirectory("../../login_data/"); + doDataSetupInDirectory("../../sp_character_data/"); +} + +sub doDataSetupInDirectory +{ + my($directory)=@_; + + open (CREATELIST,"ls ".$directory."*.sql|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); + +} + +sub doCreatesInDirectory +{ + my($directory)=@_; + + open (CREATELIST,"ls ".$directory."*.type|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); + + open (CREATELIST,"ls ".$directory."*.tab|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); + + open (CREATELIST,"ls ".$directory."*.view|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); + + open (CREATELIST,"ls ".$directory."*.seq|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); + + open (CREATELIST,"ls ".$directory."*.fkey|"); + while () + { + print $_; + chop; + system (&sqlplus." < $_ > /tmp/database_update.tmp"); + &checkError("/tmp/database_update.tmp"); + } + close (CREATELIST); +} + +# Return the sqlplus command string +sub sqlplus +{ + my ($user,$pwd,$db); + $user=$::opt_username; + $pwd=$::opt_password; + $db=$::opt_service; + $user=$ENV{"USER"} if ($user eq ""); + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + $db="swodb" if ($db eq ""); + + $user =~ tr/A-Z/a-z/; + if (($user eq "buildcluster") && !($::opt_buildcluster)) + { + die "Cannot run on buildcluster unless you use the --buildcluster option\n"; + } + + return "sqlplus $user/$pwd\@$db"; +} + +# Return the sqlplus command string with silent option +sub sqlplusSilent +{ + my ($user,$pwd,$db); + $user=$::opt_username; + $pwd=$::opt_password; + $db=$::opt_service; + $user=$ENV{"USER"} if ($user eq ""); + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + $db="swodb" if ($db eq ""); + + $user =~ tr/A-Z/a-z/; + if (($user eq "buildcluster") && !($::opt_buildcluster)) + { + die "Cannot run on buildcluster unless you use the --buildcluster option\n"; + } + + return "sqlplus -s $user/$pwd\@$db"; +} + + +# Return the sqlplus command string for the login schema +sub sqlplusForLogin +{ + my ($user,$pwd,$db); + $user=$::opt_loginusername; + $pwd=$::opt_password; + $db=$::opt_service; + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + $db="swodb" if ($db eq ""); + + $user =~ tr/A-Z/a-z/; + if (($user eq "buildcluster") && !($::opt_buildcluster)) + { + die "Cannot run on buildcluster unless you use the --buildcluster option\n"; + } + + if ($user eq "") + { + die "Must specify the login user name using --loginusername\n"; + } + + return "sqlplus $user/$pwd\@$db"; +} + +# Return the sqlplus command string for the gold schema +sub sqlplusForGold +{ + my ($user,$pwd,$db); + $user=$::opt_goldusername; + $pwd=$::opt_password; + $db=$::opt_service; + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + $db="swodb" if ($db eq ""); + + $user =~ tr/A-Z/a-z/; + if (($user eq "buildcluster") && !($::opt_buildcluster)) + { + die "Cannot run on buildcluster unless you use the --buildcluster option\n"; + } + + if ($user eq "") + { + die "Must specify the gold user name using --goldusername\n"; + } + + return "sqlplus $user/$pwd\@$db"; +} + +# Return the sqlplus command string for dba +sub sqlplusForDBA +{ + my ($user,$pwd,$db); + $user=$::opt_dbausername; + $pwd=$::opt_dbapassword; + $db=$::opt_service; + $pwd=$ENV{"DB_PASSWORD"} if ($pwd eq ""); + $pwd="changeme" if ($pwd eq ""); + $db="swodb" if ($db eq ""); + + if (!($::opt_newschema)) + { + die "Only --newschema may use DBA!\n"; + } + + if ($user eq "") + { + die "Must specify the dba user name using --newschema\n"; + } + + return "sqlplus $user/$pwd\@$db"; +} + +sub doDeltaUpdates +{ + my($fromversion,$toversion,$noversioncheck)=@_; + my($updated,$results,$error,$newversion,$version,$invalidlogin,$user,$sqlcommand); + $updated=0; + if ($fromversion) + { + $version=$fromversion; + } + else + { + $version=&getVersionNumber; + } + + while ((($toversion ne "") && ($version < $toversion)) || + (($toversion eq "") && (-e "../../updates/".($version+1).".sql"))) + { + $updated = 1; + print "Updating database to version ".($version+1)."\n"; + $results=""; + open (INFILE,&sqlplus." < ../../updates/".($version+1).".sql|"); + $error=0; + $invalidlogin=0; + while ($_=) + { + $results.=$_; + $error=1 if (/ERROR/); + $invalidlogin=1 if (/invalid username\/password; logon denied/); + } + close (INFILE); + + if ($error==1) + { + print $results."\n"; + if ($invalidlogin = 1) + { + $sqlcommand=&sqlplus; + $user=$1 if ($sqlcommand =~ /sqlplus (\w+)\//); + system("echo need to create login $user | /bin/mail -s 'create login $user' aus-db\@soe.sony.com"); + } + open (OUTFILE,"|".&sqlplus." > /dev/null"); + print OUTFILE "update version_number set version_number=$version;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + die "Could not update database from version $version to version ".($version+1)."\n"; + } + + if (!$noversioncheck) + { + $newversion=&getVersionNumber(); + if ($newversion != $version+1) + { + die "The database reports version number $newversion, but we were expecting version number ".($version+1).".\nThe database may be corrupt, or the update script may be incorrect.\n"; + } + $version=$newversion; + } + } + + return $updated; +} + +sub updatePackages +{ + #reload all the packages + + updatePackagesInDirectory("../../shared_packages/"); + updatePackagesInDirectory("../../packages/"); + updatePackagesInDirectory("../../login_packages/"); + updatePackagesInDirectory("../../sp_character_packages/"); +} + +sub updatePackagesInDirectory +{ + my($directory)=@_; + my ($user,$db,$time); + $time = time(); + $user=$::opt_username; + $db=$::opt_service; + $user=$ENV{"USER"} if ($user eq ""); + $db="swodb" if ($db eq ""); + + #headers + open (PACKAGELIST,"ls ".$directory."*.plsqlh|"); + while ($_=) + { + chop; + print "$_\n"; + open (TASK,"|".&sqlplus." > /tmp/$user.packages.$time.tmp"); + print TASK "\@".$_."\n"; + print TASK "exit\n"; + close (TASK); + &checkError ("/tmp/$user.packages.$time.tmp",1); + } + close(PACKAGELIST); + + #package bodies + open (PACKAGELIST,"ls ".$directory."*.plsql|"); + while ($_=) + { + chop; + print "$_\n"; + open (TASK,"|".&sqlplus." > /tmp/$user.packages.$time.tmp"); + print TASK "\@".$_."\n"; + print TASK "exit\n"; + close (TASK); + &checkError ("/tmp/$user.packages.$time.tmp",1); + } + close(PACKAGELIST); +} + +sub getVersionNumber +{ + my ($version); + $version = -1; + open (INFILE,&sqlplus." < getversion.sql|"); + + while ($_=) + { + if (/VERSION_NUMBER/) + { + die unless ($_=); + die unless ($_=); + chop; + $version = $_ + 0; + } + } + close (INFILE); + + die "Could not determine current version number.\n" if ($version == -1); + return $version; +} + +sub checkError +{ + my ($filename,$dontdie)=@_; + + open (CHECKFILE,$filename); + while () + { + if (/ERROR/ || /created with compilation errors/ ) + { + print; + while () + { + last if (/Disconnected from Oracle/); + print; + } + close CHECKFILE; + unlink("$filename"); + die unless $dontdie; + last; + } + } + close (CHECKFILE); + unlink("$filename"); +} + +sub doGrantPermissions +{ + system (&sqlplus." @../../queries/grant_all_permissions_to_public.sql"); +} + +sub doGrantGoldPermissions +{ + system (&sqlplusForGold." @../../queries/grant_all_permissions_to_public.sql"); +} + +sub doConfigureLimits +{ + print "\nSQL/Plus will prompt for some values:\n"; + print "\tmax_characters_per_account is the number of characters that a single account may have, across all clusters\n"; + print "\tmax_characters_per_cluster is the number of characters that a single cluster may have\n"; + print "\tcharacter_slots is the number of characters that a single account may have on one cluster\n"; + system (&sqlplusForLogin." @../../queries/configure_character_limits.sql"); +} + +sub doAddClusterForLogin +{ + system (&sqlplusForLogin." @../../queries/add_cluster.sql"); +} + +sub doExecQuery +{ + my($execquery, $time, $seq); + + #$seq = &getQuerySeq; + $seq = 0; + $time = time(); + if ($seq) + { + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + print OUTFILE "insert into automated_queries\n"; + print OUTFILE "(ID, STARTTIME, TYPE, QUERY_TEXT)\n"; + print OUTFILE "VALUES\n"; + print OUTFILE "($seq, util.unix_to_oracle_date($time,-8), 'file','$::opt_execquery');\n"; + print OUTFILE "commit;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + &checkError("/tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + } + else + { + print "Couldn't get next sequnce number for query tracking\n"; + } + + print " ../../queries/$::opt_execquery\t Started: ",scalar localtime(time()),"\n"; + open (TASK,"|".&sqlplus." > /tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + print TASK "set serveroutput on\n"; + print TASK "set timing on\n"; + print TASK "\@../../queries/$::opt_execquery\n"; + print TASK "exit;\n"; + close (TASK); + system("cat /tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + &checkError("/tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + + if ($seq) + { + $time = time(); + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + print OUTFILE "update automated_queries\n"; + print OUTFILE "set ENDTIME = util.unix_to_oracle_date($time,-8),\n"; + print OUTFILE "status = 'finished'\n"; + print OUTFILE "where ID = $seq;\n"; + print OUTFILE "commit;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + &checkError("/tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + print "\n"; + print " ../../queries/$::opt_execquery\t Finished: ",scalar localtime(time()),"\n"; + print "Query text .......\n"; + system("cat ../../queries/$::opt_execquery"); + + } + system("rm -f /tmp/execquery.$::opt_username.$::opt_service.$time.tmp"); + +} + +sub doRunOneTimeQueries +{ + my($row, $rowindex,$colindex, $column, @columns, @data, $time); + + $rowindex = 0; + $colindex = 0; + + print scalar localtime(time()),": Checking for one time queries.\n"; + + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/OneTimeQueries.tmp"); + print OUTFILE "set pagesize 0\n"; + print OUTFILE "set head off\n"; + print OUTFILE "set appi off\n"; + print OUTFILE "set show off\n"; + print OUTFILE "set sqlbl off\n"; + print OUTFILE "set sqln off\n"; + print OUTFILE "set feed off\n"; + print OUTFILE "select rtrim(to_char(id)) || ';' ||rtrim(to_char(util.oracle_to_unix_date(starttime,-8))) || ';' || rtrim(status) || ';' || rtrim(type) \n"; + print OUTFILE "|| ';' || rtrim(to_char(run_serial)) || ';' || rtrim(to_char(exec_order)) || ';' || rtrim(query_text) from automated_queries\n"; + print OUTFILE "where status = 'ready' order by exec_order;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + + + open(INFILE,"cat /tmp/OneTimeQueries.tmp |"); + while ($row = ) + { + @columns = split(/;/,$row); + foreach $column (@columns) + { + $data[$rowindex][$colindex] = $column; + + $colindex++; + } + + #print scalar localtime(time()),": Query ID: $data[$rowindex][0] - run as $data[$rowindex][3]\n"; + #print scalar localtime(time()),": Query Text: $data[$rowindex][6]"; + if ($data[$rowindex][2] ne "ready") + { + print scalar localtime(time()),": Query $data[$rowindex][0] status is $data[$rowindex][2] ... query will NOT re-execute!\n"; + } + else + { + $time = time(); + #print scalar localtime(time()),": Query $data[$rowindex][0] status is $data[$rowindex][2] starting execute!\n"; + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/database_update.tmp"); + print OUTFILE "update automated_queries set starttime = util.unix_to_oracle_date($time,-8) where ID = $data[$rowindex][0];\n"; + print OUTFILE "commit;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + &checkError("/tmp/database_update.tmp"); + + #print scalar localtime(time()),": Query $data[$rowindex][0] will be executed serially!\n"; + print " ../../queries/$data[$rowindex][6]"; + open (TASK,"|".&sqlplus." > /tmp/database_update.tmp"); + print TASK "\@../../queries/$data[$rowindex][6]\n"; + print TASK "exit\n"; + close (TASK); + &checkError("/tmp/database_update.tmp"); + + $time = time(); + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/database_update.tmp"); + print OUTFILE "update automated_queries set endtime = util.unix_to_oracle_date($time,-8) where ID = $data[$rowindex][0];\n"; + print OUTFILE "commit;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + #print scalar localtime(time()),": Query $data[$rowindex][0] execution complete!\n"; + &checkError("/tmp/database_update.tmp"); + + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/database_update.tmp"); + print OUTFILE "update automated_queries set status = 'finished' where ID = $data[$rowindex][0];\n"; + print OUTFILE "commit;\n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + &checkError("/tmp/database_update.tmp"); + + #print scalar localtime(time()),": Query $data[$rowindex][0] status is finished with no errors!\n"; + + } + + $colindex = 0; + $rowindex++; + } + + close (INFILE); + + print scalar localtime(time()),": There were $rowindex item(s) processed.\n"; + +} + +sub getQuerySeq +{ + my ($line,$time); + + $time = time(); + + open (OUTFILE,"| ".&sqlplusSilent." > /tmp/seq.$::opt_username.$::opt_service.$time.tmp"); + print OUTFILE "set pagesize 0\n"; + print OUTFILE "set head off\n"; + print OUTFILE "set appi off\n"; + print OUTFILE "set show off\n"; + print OUTFILE "set sqlbl off\n"; + print OUTFILE "set sqln off\n"; + print OUTFILE "set feed off\n"; + print OUTFILE "select rtrim(to_char(seq_queries.nextval)) from dual; \n"; + print OUTFILE "exit;\n"; + close (OUTFILE); + + open(INFILE,"cat /tmp/seq.$::opt_username.$::opt_service.$time.tmp|"); + $line = ; + close (INFILE); + $_=$line; + if (/seq_queries/) + { + return 0; + } + system("rm -f /tmp/seq.$::opt_username.$::opt_service.$time.tmp"); + return $line; + +} \ No newline at end of file