/*****************************************************************************/
/*  (c) Copyright IBM Corp. 2007 All rights reserved.
/*  
/*  The following sample of source code ("Sample") is owned by International 
/*  Business Machines Corporation or one of its subsidiaries ("IBM") and is 
/*  copyrighted and licensed, not sold. You may use, copy, modify, and 
/*  distribute the Sample in any form without payment to IBM, for the purpose of 
/*  assisting you in the development of your applications.
/*  
/*  The Sample code is provided to you on an "AS IS" basis, without warranty of 
/*  any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR 
/*  IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
/*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do 
/*  not allow for the exclusion or limitation of implied warranties, so the above 
/*  limitations or exclusions may not apply to you. IBM shall not be liable for 
/*  any damages you suffer as a result of using, copying, modifying or 
/*  distributing the Sample, even if IBM has been advised of the possibility of 
/*  such damages.
/*****************************************************************************/
/*                                                                           */
/* SAMPLE FILE NAME    : ssv_backup_tbsp.sqc                                 */
/*                                                                           */
/* PURPOSE             : This sample demonstrates performing a tablespace    */
/*                       backup in a massively parallel processing (MPP)     */
/*                       environment.                                        */
/*                                                                           */
/* USAGE SCENARIO      : This sample demonstrates different options of       */
/*                       performing tablespace BACKUPs in an MPP environment.*/
/*                       In an MPP environment, you can back up tablespaces  */
/*                       on a single database partition, on several database */
/*                       partitions at once, or on all database partitions at*/
/*                       once.                                               */
/*                                                                           */
/* PREREQUISITE        : MPP setup with 3 database partitions:               */
/*                         NODE 0: Catalog Node                              */
/*                         NODE 1: Non-catalog node                          */
/*                         NODE 2: Non-catalog node                          */
/*                                                                           */
/* EXECUTION           : ssv_backup_tbsp <log path> <store path>             */
/*                                                                           */
/* INPUTS              : <log path>   : Path to store the database logs.     */
/*                       <store path> : Path to store backup images.         */
/*                                                                           */
/* OUTPUT              : Successful tablespace backups                       */
/*                                                                           */
/*                                                                           */
/*                                    */
/*                                                                           */
/* DB2 APIs USED       : db2Backup -- BACKUP DATABASE                        */
/*                       db2CfgSet -- SET DATABASE CONFIGURATION             */
/*                       db2CfgGet -- GET DATABASE CONFIGURATION             */
/*                                                                           */
/* SQL STATEMENTS USED : CREATE DATABASE PARTITION GROUP                     */
/*                       CREATE TABLESPACE                                   */
/*                       DROP TABLESPACE                                     */
/*                       DROP DATABASE PARTITION GROUP                       */
/*                                                                           */
/*****************************************************************************/
/*For more information on the sample programs, see the README file.          */
/*For information on using SQL statements, see the SQL Reference.            */
/*                                                                           */
/*For the latest information on programming, building, and running DB2       */
/*applications, visit the DB2 Information Center:               */
/*http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp                                */
/*****************************************************************************/

/*****************************************************************************/
/* SAMPLE DESCRIPTION                                                        */
/*****************************************************************************/
/* 1.  Back up a tablespace on a set of specified database partitions        */
/*     (database partition 1 and database partition 2.)                      */
/* 2.  Back up a tablespace on all database partitions at once.              */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlenv.h>
#include <sqlutil.h>
#include <db2ApiDf.h>
#include "utilemb.h"

/* function declarations */ 
int PrepareDatabase(char *, char *, char *, char *);
int BackupTablespaceOnASetOfPartitions(char *, char *, char *, char *);
int BackupTablespaceOnAllPartitions(char *, char *, char *, char *);

char logPath[SQL_PATH_SZ + 1] = { 0 };

int main(int argc, char *argv[])
{
  int rc = 0;
  struct sqlca sqlca = { 0 };

  char dbAlias[SQL_ALIAS_SZ + 1];
  char user[USERID_SZ + 1];
  char pswd[PSWD_SZ + 1];
  char restoredDbAlias[SQL_ALIAS_SZ + 1] = { 0 };
  char workingPath[SQL_PATH_SZ + 1] = { 0 };

  /* Check the command line arguments */
  switch (argc)
  {
    case 3:
      strcpy(logPath, argv[1]);
      strcpy(workingPath, argv[2]);
      strcpy(dbAlias, "SAMPLE");
      strcpy(user, "");
      strcpy(pswd, "");
      break;

    case 4:
      strcpy(logPath, argv[2]);
      strcpy(workingPath, argv[3]);
      strcpy(dbAlias, argv[1]);
      strcpy(user, "");
      strcpy(pswd, "");
      break;

    case 6:
      strcpy(logPath, argv[4]);
      strcpy(workingPath, argv[5]);
      strcpy(dbAlias, argv[1]);
      strcpy(user, argv[2]);
      strcpy(pswd, argv[3]);
      break;

    default:
      printf("\nUSAGE: %s "
             "[dbAlias [user pswd]] "
             "<log path> <working path>\n",
             argv[0]);
      printf("       The 'log path' & 'working path' mentioned above has to be"
             " absolute & must exist.\n");
      rc = 1;
      break;
  }
  if (rc != 0)
  {
    return rc;
  }

  printf("\nTHIS SAMPLE SHOWS HOW TO PERFORM TABLESPACE BACKUP IN AN "
         "MPP ENVIRONMENT.\n");

/*****************************************************************************/
/*   SETUP                                                                   */
/*****************************************************************************/
  printf("\n***************************************************************");
  printf("\n*   SETUP                                                     *");
  printf("\n***************************************************************\n");

  /* Connect to database */
  rc = DbConn(dbAlias, user, pswd);
  if (rc != 0)
  {
    return rc;
  }

  /* Create a database partition group on database partitions 1 and 2. */

  printf("\nUse the SQL command\n");
  printf("  CREATE DATABASE PARTITION GROUP\n");
  printf("To create database partition group.\n\n");

  printf("Execute:\n");
  printf("  CREATE DATABASE PARTITION GROUP dbpgroup ON DBPARTITIONNUMS (1, 2)");

  EXEC SQL CREATE DATABASE PARTITION GROUP dbpgroup ON DBPARTITIONNUMS (1, 2);
  EMB_SQL_CHECK("CREATE DATABASE PARTITION -- Invoke");

  /* Create a tablespace on the partition group above created. */

  printf("\n\nUse the SQL command\n");
  printf("  CREATE TABLESPACE\n");
  printf("To create a tablespace.\n\n");

  printf("Execute:\n");
  printf("  CREATE TABLESPACE t1 IN dbpgroup\n");

  EXEC SQL CREATE TABLESPACE t1 IN dbpgroup;
  EMB_SQL_CHECK("CREATE TABLESPACE -- Invoke");

  /* Disconnect from database */
  rc = DbDisconn(dbAlias);
  if (rc != 0)
  {
    return rc;
  }

  rc = PrepareDatabase(dbAlias, user, pswd, workingPath);
  
  if(rc != 0)
  {
    return rc;
  }

/*****************************************************************************/
/* 1. Back up a tablespace on a specified set of database partitions.        */
/*****************************************************************************/
  printf("\n*************************************************************"
         "******************");
  printf("\n* 1. Backup tablespace on a set of database partitions."
         " (NODE 1 and NODE 2).  *");
  printf("\n*************************************************************"
         "******************\n");
  rc = BackupTablespaceOnASetOfPartitions(dbAlias, user, pswd, workingPath);

  if(rc != 0)
  {
    return rc;
  }
  
/*****************************************************************************/
/* 2. Back up a tablespace on all database partitions at once.               */
/*****************************************************************************/
  printf("\n***************************************************************");
  printf("\n*2. Backup tablespace on all database partitions.             *");
  printf("\n***************************************************************\n");
  rc = BackupTablespaceOnAllPartitions(dbAlias, user, pswd, workingPath);

  if(rc != 0)
  {
    return rc;
  }
  
/*****************************************************************************/
/*   CLEANUP                                                                 */
/*****************************************************************************/
  printf("\n***************************************************************");
  printf("\n*   CLEANUP                                                   *");
  printf("\n***************************************************************\n");
  /* Connect to database */
  rc = DbConn(dbAlias, user, pswd);
  if (rc != 0)
  {
    return rc;
  }

  /* Drop the tablespace T1 */
  printf("\nUse the SQL command\n");
  printf("  DROP TABLESPACE\n");
  printf("To drop a tablespace.\n\n");

  printf("Execute:\n");
  printf("  DROP TABLESPACE t1");

  EXEC SQL DROP TABLESPACE t1;
  EMB_SQL_CHECK("DROP TABLESPACE -- Invoke");

  /* Drop the database partition group dbpgroup */
  printf("\n\nUse the SQL command\n");
  printf("  DROP DATABASE PARTITION GROUP\n");
  printf("To drop a database partition group.\n\n");

  printf("Execute:\n");
  printf("  DROP DATABASE PARTITION GROUP dbpgroup\n");

  EXEC SQL DROP DATABASE PARTITION GROUP dbpgroup;
  EMB_SQL_CHECK("DROP DATABASE PARTITION GROUP -- Invoke");

  /* Disconnect from database */
  rc = DbDisconn(dbAlias);
  if (rc != 0)
  {
    return rc;
  }

  return 0;
} /* end main */

/*****************************************************************************/
/* Function: PrepareDatabase                                                 */
/* Prepare database for tablespace backup                                    */
/*****************************************************************************/
int PrepareDatabase(char dbAlias[], 
                    char user[], 
                    char pswd[],
                    char workingPath[])
{

  int rc = 0;
  struct sqlca sqlca = { 0 };
  db2BackupStruct backupStruct = { 0 };
  db2BackupMPPOutputStruct backupMPPOutputStruct[3] = { 0, 0, 0 };
  db2MediaListStruct mediaListStruct = { 0 };
  db2CfgParam cfgParameters[1] = { 0 };
  db2Cfg cfgStruct = { 0 };
  char archValue[SQL_PATH_SZ + 5] = { 0 };

  /* Before performing a tablespace backup, the database must be made       */
  /* recoverable. This will make the logs available which are necessary to  */
  /* restore/rollforward the tablespace. Without making the database        */
  /* recoverable, tablespace can not be backed up.                          */
  /* To make the database recoverable, set the LOGARCHMETH1 configuration   */
  /* parameter and take a full backup of the database.                      */

  printf("\n**********************************************************"
         "*************");
  printf("\nTo perform a tablespace backup, the database must be made "
         " recoverable.\n  To make the database recoverable, set the "
         " LOGARCHMETH1 configuration\n  parameter and take a full backup"
         " of the database.\n");
  printf("************************************************************"
         "***********\n");

  printf("\nUse following commands to make the database recoverable:\n"
         "  UPDATE DB CFG FOR SAMPLE USING logarchmeth1 disk:%s\n"
         "  BACKUP DB sample ON ALL DBPARTITIONNUMS\n", logPath);

  printf("\n    Update \'%s\'  database configuration:\n", dbAlias);
  printf("    - Set the database configuration parameter LOGARCHMETH1\n");
  printf("        i.e., set LOGARCHMETH1  = disk:%s\n", logPath);

  /* Initialize cfgParameters */ 

  strcpy(archValue, "disk:");
  strcat(archValue, logPath);
  /* SQLF_DBTN_LOGARCHMETH1 is a token of the updatable database       */
  /* configuration parameter 'logarchmeth1'; it is used to update the  */
  /* database configuration file                                       */
  cfgParameters[0].flags = 0;
  cfgParameters[0].token = SQLF_DBTN_LOGARCHMETH1;
  cfgParameters[0].ptrvalue = (char *)archValue;

  /* Initialize cfgStruct */
  cfgStruct.numItems = 1;
  cfgStruct.paramArray = cfgParameters;
  cfgStruct.flags = db2CfgDatabase | db2CfgImmediate;
  cfgStruct.dbname = dbAlias;

  printf("\n***********************************************\n");
  printf("***       UPDATE DB CFG PARAMETER           ***\n");
  printf("***********************************************\n");
  printf("\nUSE THE DB2 APIs:\n");
  printf("  db2CfgSet -- Update db config\n");
  printf("TO UPDATE THE DATABASE CONFIGURATION PARAMETERS.\n");

  /* Set database configuration */
  db2CfgSet(db2Version970, (void *)&cfgStruct, &sqlca);
  DB2_API_CHECK("Update DB config");

  printf("\n****************************\n");
  printf("*** BACK UP THE DATABASE ***\n");
  printf("****************************\n");
  printf("\nUSE THE DB2 APIs:\n");
  printf("  db2Backup -- Backup Database\n");
  printf("TO BACK UP THE DATABASE.\n");

  backupStruct.piDBAlias = dbAlias;
  backupStruct.piUsername = user;
  backupStruct.piPassword = pswd;
  backupStruct.piVendorOptions = NULL;
  backupStruct.iVendorOptionsSize = 0;
  backupStruct.iCallerAction = DB2BACKUP_BACKUP;

  /* DB2BACKUP_MPP & DB2BACKUP_DB specifies database level backup in an     */
  /* MPP environment.                                                       */
  backupStruct.iOptions = DB2BACKUP_MPP | DB2BACKUP_OFFLINE | DB2BACKUP_DB;
  backupStruct.iAllNodeFlag = DB2_ALL_NODES;
  backupStruct.piNodeList = NULL;
  backupStruct.iNumMPPOutputStructs = 3;
  backupStruct.poMPPOutputStruct = backupMPPOutputStruct;

  /*******************************/
  /*    BACK UP THE DATABASE    */
  /*******************************/
  printf("\n    Backing up the '%s' database...\n", dbAlias);

  mediaListStruct.locations = &workingPath;
  mediaListStruct.numLocations = 1;
  mediaListStruct.locationType = SQLU_LOCAL_MEDIA;

  backupStruct.piMediaList = &mediaListStruct;

  /* The API db2Backup creates a backup copy of a database.             */
  /* This API automatically establishes a connection to the specified   */
  /* database. (This API can also be used to create a backup copy of a  */
  /* table space).                                                      */
  db2Backup(db2Version970, &backupStruct, &sqlca);
  DB2_API_CHECK("Database -- Backup");

  printf("  Backup finished.\n");
  printf("    - backup image path      : %s\n", mediaListStruct.locations[0]);
  printf("    - backup image time stamp: %s\n", backupStruct.oTimestamp);

  return rc;

}

/*****************************************************************************/
/* Function: BackupDatabaseOnASetOfPartitions		                       */
/* Back up the database on a set of database partitions specified.           */
/*****************************************************************************/
int BackupTablespaceOnASetOfPartitions(char dbAlias[], 
                                  char user[], 
                                  char pswd[],
                                  char workingPath[])
{
  int rc = 0;
  struct sqlca sqlca = { 0 };
  db2BackupStruct backupStruct = { 0 };
  db2BackupMPPOutputStruct backupMPPOutputStruct[3] = { 0, 0, 0 };
  db2MediaListStruct mediaListStruct = { 0 };
  db2TablespaceStruct tablespaceStruct = { 0 };
  char *tablespaceList[20] = {"T1"};

  printf("\n******************************\n");
  printf("*** BACK UP THE TABLESPACE ***\n");
  printf("******************************\n");
  printf("\nUSE THE DB2 APIs:\n");
  printf("  db2Backup -- Backup Database\n");
  printf("TO BACK UP THE TABLESPACE.\n");

  backupStruct.piDBAlias = dbAlias;
  backupStruct.piUsername = user;
  backupStruct.piPassword = pswd;
  backupStruct.piVendorOptions = NULL;
  backupStruct.iVendorOptionsSize = 0;
  backupStruct.iCallerAction = DB2BACKUP_BACKUP;

  /* DB2BACKUP_MPP & DB2BACKUP_TABLESPACE specifies tablespace level backup */
  /* in an MPP environment.                                                 */
  backupStruct.iOptions = DB2BACKUP_MPP |
                          DB2BACKUP_OFFLINE |
                          DB2BACKUP_TABLESPACE;

  /* DB2_NODE_LIST specifies that the backup will be performed on the list  */
  /* of database partitions supplied as parameters.                         */
  backupStruct.iAllNodeFlag = DB2_NODE_LIST;

  /* Total number of database partitions that will take part in backup.     */
  backupStruct.iNumNodes = 2;
  backupStruct.piNodeList = (SQL_PDB_NODE_TYPE *)
                              malloc(2 * sizeof(SQL_PDB_NODE_TYPE));

    if (backupStruct.piNodeList == NULL)
  {
    printf("\nInsufficient memory.\n");
    return 1;
  }
  
  /* NODE 1 & NODE 2 will be backed up.*/
  backupStruct.piNodeList[0] = 0;
  backupStruct.piNodeList[1] = 1;
  backupStruct.iNumMPPOutputStructs = 2;
  backupStruct.poMPPOutputStruct = backupMPPOutputStruct;

  /***********************************/
  /*    BACK UP THE TABLESPACE T1    */
  /***********************************/
  printf("\n    Backing up the '%s' tablespace...\n", *tablespaceList);

  tablespaceStruct.tablespaces = tablespaceList;
  tablespaceStruct.numTablespaces = 1;

  mediaListStruct.locations = &workingPath;
  mediaListStruct.numLocations = 1;
  mediaListStruct.locationType = SQLU_LOCAL_MEDIA;

  backupStruct.piTablespaceList = &tablespaceStruct;
  backupStruct.piMediaList = &mediaListStruct;

  /* The API db2Backup is used to create a backup copy of a table space. */
  db2Backup(db2Version970, &backupStruct, &sqlca);
  DB2_API_CHECK("Tablespace -- Backup");

  printf("  Backup finished.\n");
  printf("    - backup image path      : %s\n", mediaListStruct.locations[0]);
  printf("    - backup image time stamp: %s\n", backupStruct.oTimestamp);

  free(backupStruct.piNodeList);
  
  return rc;

}

/*****************************************************************************/
/* Function: BackupDatabaseOnAllOfPartitions		                       */
/* Back up the database on all database partitions at once.                  */
/*****************************************************************************/
int BackupTablespaceOnAllPartitions(char dbAlias[], 
                                char user[], 
                                char pswd[],
                                char workingPath[])
{
  int rc = 0;
  struct sqlca sqlca = { 0 };
  db2BackupStruct backupStruct = { 0 };
  db2BackupMPPOutputStruct backupMPPOutputStruct[3] = { 0, 0, 0 };
  db2MediaListStruct mediaListStruct = { 0 };
  db2TablespaceStruct tablespaceStruct = { 0 };
  char *tablespaceList[20] = {"T1"};

  printf("\n******************************\n");
  printf("*** BACK UP THE TABLESPACE ***\n");
  printf("******************************\n");
  printf("\nUSE THE DB2 APIs:\n");
  printf("  db2Backup -- Backup Database\n");
  printf("TO BACK UP THE TABLESPACE.\n");

  backupStruct.piDBAlias = dbAlias;
  backupStruct.piUsername = user;
  backupStruct.piPassword = pswd;
  backupStruct.piVendorOptions = NULL;
  backupStruct.iVendorOptionsSize = 0;
  backupStruct.iCallerAction = DB2BACKUP_BACKUP;

  /* DB2BACKUP_MPP & DB2BACKUP_TABLESPACE specifies tablespace level backup */
  /* in an MPP environment.                                                 */
  backupStruct.iOptions = DB2BACKUP_MPP |
                          DB2BACKUP_OFFLINE |
                          DB2BACKUP_TABLESPACE;

  /* DB2_ALL_NODES specifies that the backup will be performed on all       */
  /* database partitions                                                    */
  backupStruct.iAllNodeFlag = DB2_ALL_NODES;
  backupStruct.piNodeList = NULL;

  /* Total number of database partitions that will take part in backup.     */
  backupStruct.iNumMPPOutputStructs = 3;
  backupStruct.poMPPOutputStruct = backupMPPOutputStruct;

  /*******************************/
  /*    BACK UP THE TABLESPACE    */
  /*******************************/
  printf("\n    Backing up the '%s' tablespace...\n", *tablespaceList);

  tablespaceStruct.tablespaces = tablespaceList;
  tablespaceStruct.numTablespaces = 1;

  mediaListStruct.locations = &workingPath;
  mediaListStruct.numLocations = 1;
  mediaListStruct.locationType = SQLU_LOCAL_MEDIA;

  backupStruct.piTablespaceList = &tablespaceStruct;
  backupStruct.piMediaList = &mediaListStruct;

  /* The API db2Backup is used to create a backup copy of a table space. */
  db2Backup(db2Version970, &backupStruct, &sqlca);
  DB2_API_CHECK("Tablespace -- Backup");

  printf("  Backup finished.\n");
  printf("    - backup image path      : %s\n", mediaListStruct.locations[0]);
  printf("    - backup image time stamp: %s\n", backupStruct.oTimestamp);

  return rc;

}