EIQ User Transform SDK
Version 8.0.0.490
Requirements
for Building the EIQUserTransform.DLL(Using C++) Modifying
the EIQ User Transform DLL Code Building
the EIQ User Transform DLL Defining
and Using Transforms Created by Perl or Other Scripts The EIQ Server RTI Tool allows the specification of
transforms on data columns. There are predefined and user-defined transforms.
With user-defined transforms, anyone with experience in Microsoft Visual C++ or
Perl can define and implement transforms for a specific requirement not supported
by predefined transforms. Transforms can be defined in the following two ways: In order to create user defined transforms, you must be familiar
with C++ coding and you must install a C++ compiler capable of building a Win32
DLL. Microsoft Visual C++ version 7.x is the preferred compiler. The "EIQ User Transform SDK" folder included with
the EIQ Product Suite contains a C++ project for the EIQUserTransform.DLL. This
includes two sample transforms. The location is as follows:
INSTALL_FOLDER\WhamTech\EIQ User Transform SDK The directory structure for the SDK files is shown below:
EIQ User Transform SDK\
Help\
EIQUserTransformSDK.chm
include\
EIQTransform\
EIQTransform.h
EIQTransformDefs.h
EIQUserTransform.h
lib\
EIQTransform.lib
Source\
EIQUserTransform.cpp
EIQUserTransform.vcproj
ReadMe.txt
stdafx.cpp
stdafx.h
UserTransforms.cpp
UserTransforms.h The source project, if built from the included source, produces
the same EIQUserTransform.dll included with the EIQ Server Suite installation
and is located in the INSTALL_FOLDER\WhamTech\bin
folder. To build the .dll, you must have
Microsoft Visual Studio.Net. Open or double-click the .vcproj project file. First, set the path to the ‘include’ and ‘lib’ folders.
Select "Tools | Options."
from the compiler menu. Then, select the Projects node and then VC++
Directories. Under the "Show
directories for" drop-down, select "Include files". Assuming the EIQ Server Suite was
installed in the default location, it adds the following path: C:\Program
Files\WhamTech\EIQ User Transform SDK\include Next, select "Library
files" from the drop-down and add the following path. C:\Program
Files\WhamTech\EIQ User Transform SDK\lib You can now build and modify the project as normal. The only files that must be modified when adding a new
transform are: EIQUserTransform.h EIQUserTransform.cpp UserTransforms.cpp UserTransforms.h Adding a new transform is demonstrated in the examples below.
The example adds a transform called TrimDataRight() to trim trailing spaces from character
data. The following listings show the current code from the source files with
the required modifications highlighted in RED. // The following ifdef block is the standard way of creating
macros which make exporting // from a DLL simpler. All files within this DLL are compiled
with the EIQUSERTRANSFORM_EXPORTS // symbol defined on the command line. this symbol should not be
defined on any project // that uses this DLL. This way any other project whose source
files include this file see // EIQUSERTRANSFORM_API functions as being imported from a DLL,
whereas this DLL sees symbols // defined with this macro as being exported. #ifdef EIQUSERTRANSFORM_EXPORTS #define EIQUSERTRANSFORM_API __declspec(dllexport) #else #define EIQUSERTRANSFORM_API __declspec(dllimport) #endif #if !defined(EIQUSERTRANSFORM_H) #define EIQUSERTRANSFORM_H #include <EIQTransform\EIQTransformDefs.h> class CEIQTransform; // This class is exported from the EIQUserTransform.dll class EIQUSERTRANSFORM_API CEIQUserTransform { public: CEIQUserTransform(CEIQTransform* pEIQTransform); ~CEIQUserTransform(); int ProcessTransform(const char* pszCommand); enum CommandType {CMD_REMOVECHARACTERS, CMD_MULTIPLY, CMD_TRIMDATARIGHT}; protected: CEIQTransform* m_pEIQTransform; }; #endif EIQUSERTRANSFORM_API int GetUserCommandType(const char* pszCommand); EIQUSERTRANSFORM_API USER_TRANSFORM_METHODS* GetUserTransformMethodsArray(); _______________________________________________________________________________________________ Listing 1: EIQUserTransform.h From Listing 1, add an enum for
the new transform command: CMD_TRIMDATARIGHT. // EIQUserTransform.cpp : Defines the entry point for the DLL
application. // #include "stdafx.h" #include <EIQTransform\EIQUserTransform.h> #include <EIQTransform\EIQTransform.h> #include "UserTransforms.h" USER_TRANSFORM_METHODS g_stUserTransformMethods[]
= { // User Transform Methods // szMethodName, szArgument, bArgument, eTransformType {"RemoveCharacters",
"-()", TRUE, CEIQTransform::TFCHAR},
{"Multiply", "", TRUE, -1},
// You can also combine types - // CEIQTransform::TFINT
| CEIQTransform::TFDOUBLE {"TrimDataRight", "", FALSE, CEIQTransform::TFCHAR}, // End of Record Terminator {"", "", 0, -1} }; BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved) { switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break; } return TRUE; } // Get the command type from the transform command // EIQUSERTRANSFORM_API int GetUserCommandType(const char* pszCommand) { int
iLen, iCommandType; iLen
= CEIQTransform::GetTransformCommandLength(pszCommand); if (_strnicmp(pszCommand, "RemoveCharacters", iLen) ==
0) iCommandType
= CEIQUserTransform::CMD_REMOVECHARACTERS; else if (_strnicmp(pszCommand,
"Multiply", iLen) == 0) iCommandType
= CEIQUserTransform::CMD_MULTIPLY;
else if (_strnicmp(pszCommand,
"TrimDataRight", iLen)
== 0)
iCommandType = CEIQUserTransform::CMD_TRIMDATARIGHT; else iCommandType
= CEIQTransform::CMD_INVALID; return iCommandType; } // Get the array of user transform methods // EIQUSERTRANSFORM_API USER_TRANSFORM_METHODS* GetUserTransformMethodsArray() { return g_stUserTransformMethods; } // This is the constructor of a class that has been exported. // see EIQUserTransform.h for the class
definition CEIQUserTransform::CEIQUserTransform(CEIQTransform* pEIQTransform) { m_pEIQTransform = pEIQTransform; } CEIQUserTransform::~CEIQUserTransform() { } int CEIQUserTransform::ProcessTransform(const char* pszCommand) { int iReturn = EIQTRANSFORM_SUCCESS; char szError[128]; CUserTransforms*
pUserTranforms; CommandType eCommandType; pUserTranforms
= new CUserTransforms(m_pEIQTransform); if (pUserTranforms != NULL) {
eCommandType = (CommandType)GetUserCommandType(pszCommand);
switch (eCommandType)
{
case CMD_REMOVECHARACTERS:
iReturn = pUserTranforms->RemoveCharacters(pszCommand);
break;
case CMD_MULTIPLY:
iReturn = pUserTranforms->Multiply(pszCommand);
break;
case CMD_TRIMDATARIGHT:
iReturn = pUserTranforms->TrimDataRight();
break;
case CEIQTransform::CMD_INVALID:
sprintf(szError,
"Error: Invalid command [%s] specified", pszCommand);
m_pEIQTransform->SetErrorString(szError);
iReturn = EIQTRANSFORM_ERROR;
break;
}
delete pUserTranforms; } return iReturn; } _______________________________________________________________________________________________ Listing 2: EIQUserTransform.cpp From Listing 2, add the following line to the g_stUserTransformMethods[] global array variable:
{"TrimDataRight", "", FALSE, CEIQTransform::TFCHAR}, The first entry is the method name. The second entry is the default
argument to the method. In this case, the method does not require an argument
and, therefore, "" or
NULL string. The third entry is a Boolean value to indicate if an argument is
required. In this case, it is FALSE since an argument is not required. The last
entry is an enum indicating the transform data type,
which in this case is a CHAR. Next, modify the GetUserCommandType(.) method
as follows:
else if (_strnicmp(pszCommand,
"TrimDataRight", iLen)
== 0)
iCommandType = CEIQUserTransform::CMD_TRIMDATARIGHT; If the TrimDataRight command is
passed to the GetUserCommandType() method, it returns the command type. The last modification for Listing 2 is in the ProcessTransform() method. The following lines are added:
case CMD_TRIMDATARIGHT:
iReturn = pUserTranforms->TrimDataRight(pszCommand);
break; If the TrimDataRight command is
passed to the ProcessTransform method, the correct
command is executed. #pragma once class CEIQTransform; class CUserTransforms { public: CUserTransforms(CEIQTransform* pEIQTransform); virtual ~CUserTransforms(void); // User defined transform int RemoveCharacters(const char* pszCommand); int Multiply(const char* pszCommand); int
TrimDataRight(); protected: CEIQTransform* m_pEIQTransform; }; _______________________________________________________________________________________________ Listing 3: UserTransforms.h
In the UserTransform.h header, add
the declaration for the new user-defined transform as follows: int TrimDataRight(); Next, implement the logic. This can be the hard part, but
the example is simplified. // UserTransforms.cpp : implementation of the CUserTransforms
class. // #include "StdAfx.h" #include "UserTransforms.h" #include <EIQTransform\EIQTransform.h> CUserTransforms::CUserTransforms(CEIQTransform* pEIQTransform) { m_pEIQTransform = pEIQTransform; } CUserTransforms::~CUserTransforms(void) { } // Process a RemoveCharacters(-)
command - remove the passed characters from the
string // int CUserTransforms::RemoveCharacters(const char* pszCommand) { bool bRemove; int
iReturn = EIQTRANSFORM_SUCCESS; int i, k, l; int iLen; int iCount;
// Number of characters to substitute char* pszCommandArgument; char* pszColumnValue; char* pszTransformValue; char szError[128]; if ((pszCommandArgument
= m_pEIQTransform->GetCommandArgument(pszCommand)) != NULL) { iCount
= (int)strlen(pszCommandArgument); pszColumnValue
= _strdup((const char*)m_pEIQTransform->GetColumnValue()); iLen
= (int)strlen(pszColumnValue); pszTransformValue
= new char[iLen+1]; ZeroMemory(pszTransformValue, iLen+1); // Remove characters for (i=0, l=0; i<iLen; i++) {
bRemove = false;
// Check if character should be removed
for (k=0; k<iCount; k++)
{
if (pszColumnValue[i] == pszCommandArgument[k])
{
bRemove = true;
break;
}
}
if (!bRemove)
pszTransformValue[l++] = pszColumnValue[i]; } m_pEIQTransform->SetTransformCharValue(pszTransformValue); free(pszColumnValue); delete[] pszTransformValue; } else { sprintf(szError, "Warning: Invalid RemoveCharacters
command was specified"); m_pEIQTransform->SetErrorString(szError); iReturn
= EIQTRANSFORM_ERROR; } return iReturn; } // Process a Multiply(2) command - multiply the column by the
passed value // int CUserTransforms::Multiply(const char* pszCommand) {
int iReturn =
EIQTRANSFORM_SUCCESS;
int iColumnValue;
double dMultiplier;
double dColumnValue;
char* pszCommandArgument;
char szNumericValue[256];
char szError[128];
if ((pszCommandArgument = m_pEIQTransform->GetCommandArgument(pszCommand))
!= NULL)
{
dMultiplier = atof(pszCommandArgument);
// For this transform to work with character and integer bind types you must
// check for the type
if (m_pEIQTransform->GetTransformType()
== CEIQTransform::TFCHAR)
// Get CEIQTransform::TFCHAR type value
{
iColumnValue = atoi(m_pEIQTransform->GetTransformCharValue());
// Multiply value by passed argument
iColumnValue *= (int)dMultiplier;
sprintf(szNumericValue,
"%d", iColumnValue);
m_pEIQTransform->SetTransformCharValue(szNumericValue);
}
else if (m_pEIQTransform->GetTransformType()
== CEIQTransform::TFINT) // Get CEIQTransform::TFINT type value
{
iColumnValue = m_pEIQTransform->GetTransformIntValue();
// Multiply value by passed argument
iColumnValue *= (int)dMultiplier;
m_pEIQTransform->SetTransformIntValue(iColumnValue);
}
else if (m_pEIQTransform->GetTransformType()
== CEIQTransform::TFDOUBLE)// Get CEIQTransform::TFDOUBLE type value
{
dColumnValue = m_pEIQTransform->GetTransformDoubleValue();
// Multiply value by passed argument
dColumnValue *= dMultiplier;
m_pEIQTransform->SetTransformDoubleValue(dColumnValue);
}
}
else
{
sprintf(szError,
"Warning: Invalid Multiply command was specified");
m_pEIQTransform->SetErrorString(szError);
iReturn = EIQTRANSFORM_ERROR;
}
return iReturn; } // Process a TrimDataRight()
command - remove spaces on the right // int CUserTransforms::TrimDataRight() {
int iReturn =
EIQTRANSFORM_SUCCESS;
int i, iLen;
char* pszColumnValue;
// Get the char value
if (m_pEIQTransform->GetTransformType()
== CEIQTransform::TFCHAR)
{
pszColumnValue = _strdup((const char*)m_pEIQTransform->GetColumnValue());
iLen = (int)strlen(pszColumnValue);
for (i=iLen-1; i>0; i--)
{
if (pszColumnValue [i] == '
')
pszColumnValue [i] = '\0';
else
break;
}
m_pEIQTransform->SetTransformCharValue(pszColumnValue); } return iReturn; } _______________________________________________________________________________________________ Listing 4: UserTransforms.cpp The method TrimDataRight()gets the column value and allocates
memory and stores the value in the pszColumnValue variable as follows: pszColumnValue = _strdup((const char*)
m_pEIQTransform->GetColumnValue()); Then, using basic programming logic, removes spaces from the
right side of the column value: iLen = (int)strlen(pszColumnValue); for
(i=iLen-1; i>0; i--) {
if (pszColumnValue [i] == '
')
pszColumnValue [i] = '\0';
else
break; } Next, it stores the transformed char value: m_pEIQTransform->SetTransformCharValue(pszColumnValue); You have now added a new user-defined transform. Once you have modified the code, you need to build the DLL
using the project/solution. The newly built EIQUserTransform.dll is
automatically copied to the ‘\bin’ folder using the "Post-Build Event".
The command is as follows: Release build: copy /B "$(TargetPath)" ..\..\bin Debug build: copy /B "$(TargetPath)" ..\..\bin Now, the new user transform can be accessed by EIQ Server
Suite Tools such as the EIQ Server RTI Tool. Transforms are defined using scripts written in Perl, C++,
or any other similar scripting language. To use transforms written in Perl, make sure the script file
with subroutines (named as 'perl_transforms.pl'), and the library file 'perl510.dll'
are present in the “\WhamTech\bin” folder on your local machine. A sample perl script file 'perl_transforms.pl' is already present in
your local installation 'bin' folder. Here is a description of using a sample user transform: ·
Open the EIQ Server RTI Tool and connect to the
POLICE database. ·
In profiling mode, right-click on the column
where the transform should be applied. For example, the FamilyName
column in the LOPERSON table. Select 'Transformations.' from the context menu. Figure 1: Opening the Transformations Property
sheet for the FamilyName column The 'Transformations' property sheet is displayed below: Figure 2: Transformations Property Sheet ·
Select the ‘Transformations’ tab. Figure 3: Transformations Tab ·
Click the Perlsub() transform from the 'Default Transforms' list and add it
to the left pane. Figure 4: Applying the PerlSub()
transform to the FamilyName column ·
Highlight the PerlSub() transform in the
applied Transform window and click 'Edit' to edit the transform properties. ·
Enter the name of the subroutine from the
perl_transforms.pl file, for example, 'testsub'. This
applys the transforms written in the testsub subroutine to the FamilyName
column. ·
Click ‘OK’. Figure 5: Entering the name of the Perl subroutine The 'testsub' subroutine contains
the code to transform the given string into lowercase. ·
Right Click on the FamilyName
column and select 'Preview Transform Data' to view the Transformed data. Figure 6: 'Preview Transform Data' Context Menu The preview of transformed data for the FamilyName
column should show all the column values in lowercase. Figure 7: Previewing Transformed Data User-Defined
Transforms SDK
Requirements
for Building the EIQUserTransform.DLL(Using C++)
EIQ User Transform SDK Files
Compiler
Setup
Modifying the EIQ User
Transform DLL Code
Building the EIQ User Transform DLL
Defining and Using Transforms
Created by Perl or Other Scripts
Copyright
© 2023 , WhamTech, Inc. All rights reserved. This document is
provided for information purposes only and the contents hereof are subject to
change without notice. Names may be trademarks of their respective owners.