/************************************************************************** * * Copyright (c) 2003 Informatica Corporation. This file contains * material proprietary to Informatica Corporation and may not be copied * or distributed in any form without the written permission of Informatica * Corporation * **************************************************************************//************************************************************************** * Custom Transformation p_GetSeqVal Procedure File * * This file contains code that functions that will be called by the main * server executable. * * For more information on these files, * see $(PM_HOME)/ExtProc/include/Readme.txt **************************************************************************//************************************************************************** Includes **************************************************************************/#include "p_GetSeqVal.h"#include <stdio.h>#include <string.h>#include <stdlib.h>#include <windows.h>#include <stdarg.h>#include <process.h>/************************************************************************** UserDefineMacro **************************************************************************/#define DLLNAME "SeqGenerator.dll"#define PMDTM "pmdtm.exe"#define EXTPROCDIR "ExtProc\\"#define SEQFILE "SeqGenerator.tsv"#define LOCKFILE "SeqGenerator.lock"#define SEQNAMELEN 100#define MAXSEQNUM 10000typedef unsigned long int seqval_t;#define MSGCHARS 1000#define MAX_LINE_SIZE 1000#define MSGMARK ">>>>>>>>>>>>>>>"#define PROCNAME "SeqGenerator"/************************************************************************** SharedVariables **************************************************************************/struct seq_t{char chSeqName[SEQNAMELEN+1];seqval_t nSeqVal;};struct seqlist_t{struct seq_t arrSequences[MAXSEQNUM];int nSeqNums;};#pragma data_seg("SeqGeneratorShared")static int nInitFlag=0;static int nRefCount=0;static struct seqlist_t strSeqList={0};#pragma data_seg()#pragma comment(linker,"/section:SeqGeneratorShared,rws") /************************************************************************** Debug switch **************************************************************************///#define DEBUG_MODE#ifdef DEBUG_MODE //LogMessage("%s DebugLog:",MSGMARK);#endif/************************************************************************** Global Variables **************************************************************************/char chLogMsg[MSGCHARS],chMutexName[MSGCHARS];TCHAR szPath[MAX_PATH],dllDir[MAX_PATH],SeqFilePath[MAX_PATH],LockFilePath[MAX_PATH];FILE *fpSeqFile,*fpLockFile;char *rowSeqName;char chSeqName[SEQNAMELEN+1];seqval_t nSeqVal;struct seqcache_t{char chSeqName[SEQNAMELEN+1];seqval_t *ptrSeqVal;};struct seqlistcache_t{struct seqcache_t arrSequences[MAXSEQNUM];int nSeqNums;};struct seqlistcache_t strSeqListCache={0};//HANDLE hMutex;/************************************************************************** Functions **************************************************************************/int LogMessage(char *fmt,...){ va_list ptrArg;va_start(ptrArg,fmt);vsprintf(chLogMsg,fmt,ptrArg);va_end(ptrArg);INFA_CTLogMessageM( eESL_LOG,chLogMsg);return 0;}int GetFileNumRows(FILE* fp){ int i = 0; char strLine[MAX_LINE_SIZE]; fseek(fp,0,SEEK_SET); while (fgets(strLine, MAX_LINE_SIZE, fp)) i++; fseek(fp,0,SEEK_SET); return i;}char * left(char *dst,char *src, int n){ char *p = src; char *q = dst; int len = strlen(src); if(n>len) n = len; while(n--) *(q++) = *(p++); *(q++)=‘\0‘; return dst;}char * mid(char *dst,char *src, int n,int m) { char *p = src; char *q = dst; int len = strlen(src); if(m>len) m = len-n; if(n<0) n=0; if(n>len) return NULL; p += n; while(m--) *(q++) = *(p++); *(q++)=‘\0‘; return dst;}/*INFA_STATUS mGetMutex(){ while(1){ hMutex=CreateMutex(NULL,FALSE,PROCNAME);if(hMutex&&GetLastError()==ERROR_ALREADY_EXISTS){ if(hMutex!=NULL){ CloseHandle(hMutex);}Sleep(1000);continue;} else if(hMutex!=NULL){ break;}else {return INFA_FAILURE;}}return INFA_SUCCESS;}*//************************************************************************** Function: p_GetSeqVal_procInit Description: Initialization for the procedure. Returns INFA_SUCCESS if procedure initialization succeeds, else return INFA_FAILURE. Input: procedure - the handle for the procedure Output: None Remarks: This function will get called once for the session at initialization time. It will be called after the moduleInit function. **************************************************************************/INFA_STATUS p_GetSeqVal_procInit( INFA_CT_PROCEDURE_HANDLE procedure){//Sleep(10000); INFA_CTChangeStringMode( procedure, eASM_MBCS );if( !GetModuleFileName( NULL, szPath, MAX_PATH ) ){ LogMessage("GetModuleFileName failed (%d)\n", GetLastError()); return INFA_FAILURE;} else {LogMessage("ModuleFileName is : %s\n", szPath);mid(dllDir,szPath,0,strlen(szPath)-strlen(PMDTM));strcat(dllDir,EXTPROCDIR);LogMessage("ModuleDirectory is : %s\n", dllDir);strcpy(SeqFilePath,dllDir);strcat(SeqFilePath,SEQFILE);LogMessage("Sequence File is : %s\n", SeqFilePath);strcpy(LockFilePath,dllDir);strcat(LockFilePath,LOCKFILE);LogMessage("Lock File is : %s\n", LockFilePath);}//CreateMutex(NULL,FALSE,PROCNAME);//mGetMutex();//WaitForSingleObject(hMutex, INFINITE);fpLockFile=fopen(LockFilePath,"w");while(LockFile(fpLockFile,1,1,1,1)!=0){Sleep(2000);}if(1==++nRefCount){int nFileNumRows,i; LogMessage("%s Loading Sequence File\n",MSGMARK); fpSeqFile=fopen(SeqFilePath,"a+"); nFileNumRows=GetFileNumRows(fpSeqFile);LogMessage("%s Sequence Objects Nums: %d\n",MSGMARK,nFileNumRows);strSeqList.nSeqNums=0;for(i=0;i<nFileNumRows;i++){fscanf(fpSeqFile,"%s\t%lu\n",chSeqName,&nSeqVal);strSeqList.nSeqNums++;strcpy(strSeqList.arrSequences[i].chSeqName,chSeqName);strSeqList.arrSequences[i].nSeqVal=nSeqVal;}if(EOF==fclose(fpSeqFile)){ LogMessage("Close Sequence File Failed!\n" ); return INFA_FAILURE; }nInitFlag=1;//CloseHandle(hMutex);LogMessage("%s Finish loading Sequence File",MSGMARK);} else {LogMessage("%s Wait for loading Sequence File",MSGMARK);while(1!=nInitFlag){}LogMessage("%s Finish loading Sequence File",MSGMARK);}UnlockFile(fpLockFile,1,1,1,1);if(EOF==fclose(fpLockFile)){ LogMessage("Close Lock File Failed!\n" );return INFA_FAILURE;}//ReleaseMutex(hMutex); return INFA_SUCCESS;}/************************************************************************** Function: p_GetSeqVal_procDeinit Description: Deinitialization for the procedure. Returns INFA_SUCCESS if procedure deinitialization succeeds, else return INFA_FAILURE. Input: procedure - the handle for the procedure Output: None Remarks: This function will get called once for the session at deinitialization time. It will be called before the moduleDeinit function. **************************************************************************/INFA_STATUS p_GetSeqVal_procDeinit( INFA_CT_PROCEDURE_HANDLE procedure, INFA_STATUS sessionStatus ){//mGetMutex();//WaitForSingleObject(hMutex, INFINITE);fpLockFile=fopen(LockFilePath,"w");while(LockFile(fpLockFile,1,1,1,1)!=0){Sleep(2000);}if(0==--nRefCount){int i;LogMessage("%s Writing Sequence File",MSGMARK);fpSeqFile=fopen(SeqFilePath,"w");for(i=0;i<strSeqList.nSeqNums;i++){fprintf(fpSeqFile,"%s\t%lu\n",strSeqList.arrSequences[i].chSeqName,strSeqList.arrSequences[i].nSeqVal);}if(EOF==fclose(fpSeqFile)){LogMessage("Close Sequence File Failed!\n" );return INFA_FAILURE;}LogMessage("%s Finish Writing Sequence File",MSGMARK);} UnlockFile(fpLockFile,1,1,1,1);if(EOF==fclose(fpLockFile)){ LogMessage("Close Lock File Failed!\n" );return INFA_FAILURE;}//ReleaseMutex(hMutex);//CloseHandle(hMutex); return INFA_SUCCESS;}/************************************************************************** Function: p_GetSeqVal_partitionInit Description: Initialization for the partition. Returns INFA_SUCCESS if partition deinitialization succeeds, else return INFA_FAILURE. Input: partition - the handle for the partition Output: None Remarks: This function will get called once for each partition for each transformation in the session. **************************************************************************/INFA_STATUS p_GetSeqVal_partitionInit( INFA_CT_PARTITION_HANDLE partition ){ /*TODO: fill in code here*/ return INFA_SUCCESS;}/************************************************************************** Function: p_GetSeqVal_partitionDeinit Description: Deinitialization for the partition. Returns INFA_SUCCESS if partition deinitialization succeeds, else return INFA_FAILURE. Input: partition - the handle for the partition Output: None Remarks: This function will get called once for each partition for each transformation in the session. **************************************************************************/INFA_STATUS p_GetSeqVal_partitionDeinit( INFA_CT_PARTITION_HANDLE partition ){ /*TODO: fill in code here*/ return INFA_SUCCESS;}/************************************************************************** Function: p_GetSeqVal_inputRowNotification Description: Notification that a row needs to be processed for an input group in a transformation for the given partition. Returns INFA_ROWSUCCESS if the input row was processed successfully, INFA_ROWERROR if the input row was not processed successfully and INFA_FATALERROR if the input row causes the session to fail. Input: partition - the handle for the partition for the given row group - the handle for the input group for the given row Output: None Remarks: This function is probably where the meat of your code will go, as it is called for every row that gets sent into your transformation. **************************************************************************/INFA_ROWSTATUS p_GetSeqVal_inputRowNotification( INFA_CT_PARTITION_HANDLE partition, INFA_CT_INPUTGROUP_HANDLE inputGroup ){ const INFA_CT_OUTPUTGROUP_HANDLE* outputGroups = NULL; const INFA_CT_INPUTPORT_HANDLE* inputGroupPorts = NULL; const INFA_CT_OUTPUTPORT_HANDLE* outputGroupPorts = NULL; size_t nNumInputPorts = 0, nNumOutputGroups = 0, nNumPortsInOutputGroup = 0;int i,j;outputGroups = INFA_CTGetChildrenHandles(partition,&nNumOutputGroups,OUTPUTGROUPTYPE);outputGroupPorts = INFA_CTGetChildrenHandles(outputGroups[0],&nNumPortsInOutputGroup,OUTPUTPORTTYPE);inputGroupPorts = INFA_CTGetChildrenHandles(inputGroup,&nNumInputPorts,INPUTPORTTYPE); rowSeqName=(char*)INFA_CTGetDataVoid(inputGroupPorts[0]);for(j=0;j<strSeqListCache.nSeqNums;j++){ if(strcmp(rowSeqName,strSeqListCache.arrSequences[j].chSeqName)==0)break;}if(j==strSeqListCache.nSeqNums){for(i=0;i<strSeqList.nSeqNums;i++){if(strcmp(rowSeqName,strSeqList.arrSequences[i].chSeqName)==0)break;}if(i==strSeqList.nSeqNums){strcpy(strSeqList.arrSequences[i].chSeqName,rowSeqName);strSeqList.nSeqNums++;strcpy(strSeqListCache.arrSequences[j].chSeqName,rowSeqName); strSeqListCache.arrSequences[j].ptrSeqVal=&(strSeqList.arrSequences[i].nSeqVal); strSeqListCache.nSeqNums++;}nSeqVal=++(strSeqList.arrSequences[i].nSeqVal);strcpy(strSeqListCache.arrSequences[j].chSeqName,rowSeqName);strSeqListCache.arrSequences[j].ptrSeqVal=&(strSeqList.arrSequences[i].nSeqVal);strSeqListCache.nSeqNums++;} else {nSeqVal=++*(strSeqListCache.arrSequences[j].ptrSeqVal);} INFA_CTSetData(outputGroupPorts[0], &nSeqVal);INFA_CTSetIndicator(outputGroupPorts[0],INFA_DATA_VALID); return INFA_CTOutputNotification(outputGroups[0]);}/************************************************************************** Function: p_GetSeqVal_eofNotification Description: Notification that the last row for an input group has already been seen. Return INFA_FAILURE if the session should fail as a result of seeing this notification, INFA_SUCCESS otherwise. Input: partition - the handle for the partition for the notification group - the handle for the input group for the notification Output: None **************************************************************************/INFA_STATUS p_GetSeqVal_eofNotification( INFA_CT_PARTITION_HANDLE partition, INFA_CT_INPUTGROUP_HANDLE group){ /*TODO: fill in code here*/ return INFA_SUCCESS;}/************************************************************************** Function: p_GetSeqVal_dataBdryNotification Description: Notification that a transaction has ended. The data boundary type can either be commit or rollback. Return INFA_FAILURE if the session should fail as a result of seeing this notification, INFA_SUCCESS otherwise. Input: partition - the handle for the partition for the notification transactionType - commit or rollback Output: None **************************************************************************/INFA_STATUS p_GetSeqVal_dataBdryNotification ( INFA_CT_PARTITION_HANDLE partition, INFA_CT_DATABDRY_TYPE transactionType){ /*TODO: fill in code here*/ return INFA_SUCCESS;}