/**************************************************************************** ** (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 no database connection read log ** ** 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 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 ****************************************************************************/ #ifdef DB2NT #include "utilrecov.cxx" #else #include "utilrecov.C" #endif class DbLognoconn: public UtilRecov, public UtilLog { public: int DbReadLogRecordsNoConn(DbEmb *, Instance *, char *, char *); }; int DbLognoconn::DbReadLogRecordsNoConn(DbEmb *db, Instance *inst, char user[], char pswd[]) { int rc = 0; struct sqlca sqlca = { 0 }; char logPath[SQL_PATH_SZ + 1] = { 0 }; db2CfgParam cfgParameters[1] = { 0 }; db2Cfg cfgStruct = { 0 }; char nodeName[] = "NODE0000\0"; db2Uint32 readLogMemSize = 16 * 4096; 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 }; cout << "\n*********************************" << endl; cout << "*** NO DB CONNECTION READ LOG ***" << endl; cout << "*********************************" << endl; cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE DB2 APIs:" << endl; cout << " db2ArchiveLog -- Archive the active log files" << endl; cout << " db2ReadLogNoConnInit -- Initialize reading the database"; cout << " logs without a db connection" << endl; cout << " db2ReadLogNoConn -- Read the database logs without a db"; cout << " connection" << endl; cout << " db2ReadLogNoConnTerm -- Terminate reading the database logs"; cout << " without a db connection" << endl; cout << "TO READ LOG RECORDS FROM THE ARCHIVED LOG DIRECTORY." << endl; // Determine the logpath to read log files from cfgParameters[0].flags = 0; cfgParameters[0].token = SQLF_DBTN_LOGARCHMETH1; cfgParameters[0].ptrvalue = new char[SQL_PATH_SZ + 1]; // Initialize cfgStruct cfgStruct.numItems = 1; cfgStruct.paramArray = cfgParameters; cfgStruct.flags = db2CfgDatabase; cfgStruct.dbname = db->getAlias(); db2CfgGet(db2Version970, (void *)&cfgStruct, &sqlca); DB2_API_CHECK("log path -- get"); strcpy(logPath, cfgParameters[0].ptrvalue + 5); strcat(logPath, inst->getNode()); strcat(logPath, "/SAMPLE/NODE0000/C0000000/"); delete [] (cfgParameters[0].ptrvalue); // Connect to the database rc = db->Connect(); CHECKRC(rc, "db->Connect"); // Invoke the SQL statements for filling database log cout << "\n Invoke the following SQL statements:\n" " ALTER TABLE emp_resume DATA CAPTURE CHANGES;\n" " COMMIT;\n" " INSERT INTO emp_resume\n" " VALUES('000120', 'ascii', 'This is a new resume');\n" " ('000030', 'ascii', 'This is another new resume');\n" " COMMIT;\n" " DELETE FROM emp_resume WHERE empno = '000120';\n" " DELETE FROM emp_resume WHERE empno = '000030';\n" " COMMIT;\n" " DELETE FROM emp_resume WHERE empno = '000140';\n" " ROLLBACK;\n" " ALTER TABLE emp_resume DATA CAPTURE NONE;\n" " COMMIT;" << endl; 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 = db->Disconnect(); CHECKRC(rc, "db->Disconnect"); // detach from the local or remote instance before reading log information rc = inst->Detach(); CHECKRC(rc, "inst->Detach"); // Invoke the db2ArchiveLog API to archive the active logs archiveLogInput.piDatabaseAlias = db->getAlias(); archiveLogInput.piUserName = user; archiveLogInput.piPassword = pswd; archiveLogInput.iAllNodeFlag = (int)NULL; archiveLogInput.iNumNodes = (int)NULL; archiveLogInput.piNodeList = NULL; archiveLogInput.iOptions =(int)NULL; rc = 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 readLogMemory = new char[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 = db->getAlias(); readLogInit.piNodeName = nodeName; readLogInit.iReadLogMemoryLimit = readLogMemSize; readLogInit.poReadLogMemPtr = &readLogMemory; rc = 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; rc = db2ReadLogNoConn(db2Version970, &readLogInput, &sqlca); if (sqlca.sqlcode != 0) { DB2_API_CHECK("database logs no db conn -- query"); } // Read some log records logBufferSize = 64 * 1024; logBuffer = new char[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; rc = 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) { cout << "\n Database log empty.\n" << endl; } } // 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 from the database logs, and // read the next log sequence asynchronously. rc = 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"); } cout << "\nRead to end of logs.\n\n" << endl; delete [] logBuffer; // Invoke the db2ReadLogNoConnTerm API to terminate reading the logs readLogTerm.poReadLogMemPtr = &readLogMemory; rc = db2ReadLogNoConnTerm(db2Version970, &readLogTerm, &sqlca); if (sqlca.sqlcode != 0) { DB2_API_CHECK("database logs no db conn -- terminate"); } return 0; } // DbLognoconn::DbReadLogRecordsNoConn int main(int argc, char *argv[]) { int rc = 0; CmdLineArgs check; char serverWorkingPath[SQL_PATH_SZ + 1] = { 0 }; sqluint16 savedLogRetainValue = 0; Instance inst; DbEmb db; char user[USERID_SZ + 1] = {0}; char pswd[PSWD_SZ + 1] = {0}; strcpy(user, argv[3]); strcpy(pswd, argv[4]); DbLognoconn dblognoconn; // check the command line arguments rc = check.CmdLineArgsCheck3(argc, argv, db, inst); CHECKRC(rc, "check.CmdLineArgsCheck3"); cout << "\nTHIS SAMPLE SHOWS HOW TO READ DATABASE LOGS ASYNCHRONOUSLY" << endl; cout << "WITH NO DATABASE CONNECTION." << endl; // attach to a local or remote instance rc = inst.Attach(); CHECKRC(rc, "inst.Attach"); // get a server working path rc = dblognoconn.ServerWorkingPathGet(&db, serverWorkingPath); CHECKRC(rc, "dblognoconn.ServerWorkingPathGet"); // Call the function to prune the history files rc = dblognoconn.DbRecoveryHistoryFilePrune(&db); CHECKRC(rc, "restore.DbRecoveryHistoryFilePrune"); // Call the routine to read the log records for no db connection. rc = dblognoconn.DbReadLogRecordsNoConn(&db, &inst, user, pswd); CHECKRC(rc, "dblognoconn.DbReadLogRecordsNoConn"); return 0; } // main