/**************************************************************************** ** (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. ***************************************************************************** ** ** SOURCE FILE NAME: dblognoconn.sqc ** ** SAMPLE: How to read the database logs with no database connection ** ** Archive logging needs to be enabled to read database logs when there is ** no connection to the database. The database logs are archived and read ** from the archive location. ** ** PREREQUISITES : Update the db cfg parameter to enable archive logging : ** ** db2 UPDATE DB CFG FOR SAMPLE USING LOGARCHMETH1 DISK:<archive log path> ** <archive log path> : path with write permission where the ** database logs can be archived ** db2 TERMINATE ** db2 BACKUP DB SAMPLE ** ** Note : You must be disconnected from the sample database to run this ** program. To ensure you are, enter 'db2 CONNECT RESET' on the ** command line prior to running the sample. ** ** EXECUTION : dblognoconn <db name> <nodename> <username> <pswd> ** ** Note : Perform 'db2 RESET DB CFG FOR SAMPLE' after running the sample ** ** DB2 APIs USED: ** db2CfgGet -- Get db configuration parameters ** db2ArchiveLog -- Archive the active log files ** db2ReadLogNoConn -- Read the database logs without a db connection ** db2ReadLogNoConnInit -- Initialize reading the database logs ** without a db connection ** db2ReadLogNoConnTerm -- Terminate reading the database logs ** without a db connection ** ** ***************************************************************************** ** ** For detailed information about database backup and database recovery, see ** the Data Recovery and High Availability Guide and Reference. This manual ** will help you to determine which database and table space recovery methods ** are best suited to your business environment. ** ** For more information on the sample programs, see the README file. ** ** For information on developing C applications, see the Application ** Development Guide. ** ** For information on using SQL statements, see the SQL Reference. ** ** For information on DB2 APIs, see the Administrative API 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 ****************************************************************************/ #include "utilrecov.c" #include "utilemb.h" /* local function prototypes */ int DbReadLogRecordsNoConn(char *, char *, char *, char *, char *); int main(int argc, char *argv[]) { int rc = 0; char nodeName[SQL_INSTNAME_SZ + 1] = { 0 }; char serverWorkingPath[SQL_PATH_SZ + 1] = { 0 }; char dbAlias[SQL_ALIAS_SZ + 1] = { 0 }; char user[USERID_SZ + 1] = { 0 }; char pswd[PSWD_SZ + 1] = { 0 }; /* check the command line arguments */ rc = CmdLineArgsCheck3(argc, argv, dbAlias, nodeName, user, pswd); CHECKRC(rc, "CmdLineArgsCheck3"); printf("\nTHIS SAMPLE SHOWS HOW TO READ DATABASE LOGS ASYNCHRONOUSLY\n"); printf("WITH NO DATABASE CONNECTION.\n"); /* attach to a local or remote instance */ rc = InstanceAttach(nodeName, user, pswd); CHECKRC(rc, "Instance Attach"); /* get the server working path */ rc = ServerWorkingPathGet(dbAlias, serverWorkingPath); CHECKRC(rc, "ServerWorkingPathGet"); /* call the routine to prune the history files */ rc = DbRecoveryHistoryFilePrune(dbAlias, user, pswd); CHECKRC(rc, "DbRecoveryHistoryFilePrune"); /* call the routine to read the log records for no db connection */ rc = DbReadLogRecordsNoConn(dbAlias, nodeName, user, pswd, serverWorkingPath); CHECKRC(rc, "DbReadLogRecordsNoConn"); return 0; } /* end main */ int DbReadLogRecordsNoConn(char dbAlias[], char nodeName[], char user[], char pswd[], char serverWorkingPath[]) { int rc = 0; struct sqlca sqlca = { 0 }; char logPath[SQL_PATH_SZ + 1] = { 0 }; db2CfgParam cfgParameters[1] = { 0 }; db2Cfg cfgStruct = { 0 }; char nodeNum[] = "NODE0000\0"; db2Uint32 readLogMemSize = 0; char *readLogMemory = NULL; struct db2ArchiveLogStruct archiveLogInput = { 0 }; struct db2ReadLogNoConnInitStruct readLogInit = { 0 }; struct db2ReadLogNoConnInfoStruct readLogInfo = { 0 }; struct db2ReadLogNoConnStruct readLogInput = { 0 }; db2LSN startLSN; db2LSN endLSN; char *logBuffer = NULL; db2Uint32 logBufferSize = 0; struct db2ReadLogNoConnTermStruct readLogTerm = { 0 }; printf("\n*********************************\n"); printf("*** NO DB CONNECTION READ LOG ***\n"); printf("*********************************\n"); printf("\nUSE THE DB2 APIs:\n"); printf(" db2ArchiveLog -- Archive the active log files\n"); printf(" db2ReadLogNoConnInit -- Initialize reading the database "); printf("logs without a db connection\n"); printf(" db2ReadLogNoConn -- Read the database logs without a db connection\n"); printf(" db2ReadLogNoConnTerm -- Terminate reading the database logs "); printf("without a db connection\n"); printf("TO READ LOG RECORDS FROM THE ARCHIVED LOG DIRECTORY.\n"); /* Determine the logpath to read log files from */ cfgParameters[0].flags = 0; cfgParameters[0].token = SQLF_DBTN_LOGARCHMETH1; cfgParameters[0].ptrvalue = (char *)malloc((SQL_PATH_SZ + 1) * sizeof(char)); /* Initialize cfgStruct */ cfgStruct.numItems = 1; cfgStruct.paramArray = cfgParameters; cfgStruct.flags = db2CfgDatabase; cfgStruct.dbname = dbAlias; db2CfgGet(db2Version970, (void *)&cfgStruct, &sqlca); DB2_API_CHECK("log path -- get"); strcpy(logPath, cfgParameters[0].ptrvalue + 5); strcat(logPath, nodeName); strcat(logPath, "\\SAMPLE\\NODE0000\\C0000000\\"); free(cfgParameters[0].ptrvalue); cfgParameters[0].ptrvalue = NULL; /* connect to the database */ rc = DbConn(dbAlias, user, pswd); CHECKRC(rc, "DbConn"); /* Invoke the SQL statements to fill the database log */ printf("\n Invoke the following SQL statements:\n"); printf(" ALTER TABLE emp_resume DATA CAPTURE CHANGES;\n"); printf(" COMMIT;\n"); printf(" INSERT INTO emp_resume\n"); printf(" VALUES('000120', 'ascii', 'This is a new resume.');\n"); printf(" ('000030', 'ascii', 'This is another new resume');\n"); printf(" COMMIT;\n"); printf(" DELETE FROM emp_resume WHERE empno = '000120';\n"); printf(" DELETE FROM emp_resume WHERE empno = '000030';\n"); printf(" COMMIT;\n"); printf(" DELETE FROM emp_resume WHERE empno = '000140';\n"); printf(" ROLLBACK;\n"); printf(" ALTER TABLE emp_resume DATA CAPTURE NONE;\n"); printf(" COMMIT;\n"); EXEC SQL ALTER TABLE emp_resume DATA CAPTURE CHANGES; EMB_SQL_CHECK("SQL statement 1 -- invoke"); EXEC SQL COMMIT; EMB_SQL_CHECK("SQL statement 2 -- invoke"); EXEC SQL INSERT INTO emp_resume VALUES('000120', 'ascii', 'This is a new resume.'), ('000030', 'ascii', 'This is another new resume'); EMB_SQL_CHECK("SQL statement 3 -- invoke"); EXEC SQL COMMIT; EMB_SQL_CHECK("SQL statement 4 -- invoke"); EXEC SQL DELETE FROM emp_resume WHERE empno = '000120'; EMB_SQL_CHECK("SQL statement 5 -- invoke"); EXEC SQL DELETE FROM emp_resume WHERE empno = '000030'; EMB_SQL_CHECK("SQL statement 6 -- invoke"); EXEC SQL COMMIT; EMB_SQL_CHECK("SQL statement 7 -- invoke"); EXEC SQL DELETE FROM emp_resume WHERE empno = '000140'; EMB_SQL_CHECK("SQL statement 8 -- invoke"); EXEC SQL ROLLBACK; EMB_SQL_CHECK("SQL statement 9 -- invoke"); EXEC SQL ALTER TABLE emp_resume DATA CAPTURE NONE; EMB_SQL_CHECK("SQL statement 10 -- invoke"); EXEC SQL COMMIT; EMB_SQL_CHECK("SQL statement 11 -- invoke"); /* Disconnect from the database */ rc = DbDisconn(dbAlias); CHECKRC(rc, "DbDisconn"); /* Detach from the local or remote instance before reading log information */ rc = InstanceDetach(nodeName); CHECKRC(rc, "InstanceDetach"); /* Invoke the db2ArchiveLog API to archive the active logs */ archiveLogInput.piDatabaseAlias = dbAlias; archiveLogInput.piUserName = user; archiveLogInput.piPassword = pswd; archiveLogInput.iAllNodeFlag = (int)NULL; archiveLogInput.iNumNodes = (int)NULL; archiveLogInput.piNodeList = NULL; archiveLogInput.iOptions = (int)NULL; db2ArchiveLog(db2Version970, &archiveLogInput, &sqlca); if (sqlca.sqlcode != 0) { DB2_API_CHECK("database archive -- archive logs"); } /* Allocate memory for the API's control blocks and log * buffer */ readLogMemSize = 16 * 4096; readLogMemory = (char *)malloc(readLogMemSize); /* Invoke the initialization API to set up the control blocks */ readLogInit.iFilterOption = DB2READLOG_FILTER_ON; readLogInit.piLogFilePath = logPath; readLogInit.piOverflowLogPath = NULL; readLogInit.iRetrieveLogs = DB2READLOG_RETRIEVE_OFF; readLogInit.piDatabaseName = dbAlias; readLogInit.piNodeName = nodeNum; readLogInit.iReadLogMemoryLimit = readLogMemSize; readLogInit.poReadLogMemPtr = &readLogMemory; db2ReadLogNoConnInit(db2Version970, &readLogInit, &sqlca); if (sqlca.sqlcode != SQLU_RLOG_LSNS_REUSED) { DB2_API_CHECK("database logs no db conn -- initialization"); } /* Invoke the db2ReadLogNoConn API to query the current log information */ readLogInput.iCallerAction = DB2READLOG_QUERY; readLogInput.piStartLSN = NULL; readLogInput.piEndLSN = NULL; readLogInput.poLogBuffer = NULL; readLogInput.iLogBufferSize = 0; readLogInput.piReadLogMemPtr = readLogMemory; readLogInput.poReadLogInfo = &readLogInfo; db2ReadLogNoConn(db2Version970, &readLogInput, &sqlca); if (sqlca.sqlcode != 0) { DB2_API_CHECK("database logs no db conn -- query"); } /* Read some log records */ logBufferSize = 64 * 1024; /* Maximum size of a log buffer */ logBuffer = (char *)malloc(logBufferSize); memcpy(&startLSN, &(readLogInfo.nextStartLSN), sizeof(startLSN)); endLSN.lsnU64 = 0xffffffffffffffff; readLogInput.iCallerAction = DB2READLOG_READ; readLogInput.piStartLSN = &startLSN; readLogInput.piEndLSN = &endLSN; readLogInput.poLogBuffer = logBuffer; readLogInput.iLogBufferSize = logBufferSize; readLogInput.piReadLogMemPtr = readLogMemory; readLogInput.poReadLogInfo = &readLogInfo; db2ReadLogNoConn(db2Version970, &readLogInput, &sqlca); if (sqlca.sqlcode != SQLU_RLOG_READ_TO_CURRENT) { DB2_API_CHECK("database logs no db conn -- read"); } else { if (readLogInfo.logRecsWritten == 0) { printf("\n Database log empty.\n"); } } /* Display the log records */ rc = LogBufferDisplay(logBuffer, readLogInfo.logRecsWritten, 0); CHECKRC(rc, "LogBufferDisplay"); while (sqlca.sqlcode != SQLU_RLOG_READ_TO_CURRENT) { /* read the next log sequence */ memcpy(&startLSN, &(readLogInfo.nextStartLSN), sizeof(startLSN)); /* Extract a log record and read the next log sequence asynchronously */ db2ReadLogNoConn(db2Version970, &readLogInput, &sqlca); if (sqlca.sqlcode != SQLU_RLOG_READ_TO_CURRENT) { DB2_API_CHECK("database logs no db conn -- read"); } /* display log buffer */ rc = LogBufferDisplay(logBuffer, readLogInfo.logRecsWritten, 0); CHECKRC(rc, "LogBufferDisplay"); } printf("\nRead to end of logs.\n\n"); free(logBuffer); logBuffer = NULL; logBufferSize = 0; /* Invoke the db2ReadLogNoConnTerm API to terminate reading the logs */ readLogTerm.poReadLogMemPtr = &readLogMemory; db2ReadLogNoConnTerm(db2Version970, &readLogTerm, &sqlca); DB2_API_CHECK("database logs no db conn -- terminate"); return 0; } /* DbReadLogRecordsNoConn */