Home page  

Help > SDK Help >

EIQ User Transform SDK

Version 8.0.0.490

User-Defined Transforms SDK.. 1

Requirements for Building the EIQUserTransform.DLL(Using C++) 1

EIQ User Transform SDK Files. 1

Compiler Setup. 2

Modifying the EIQ User Transform DLL Code. 2

Building the EIQ User Transform DLL. 8

Defining and Using Transforms Created by Perl or Other Scripts. 8

User-Defined Transforms SDK

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:

 

Requirements for Building the EIQUserTransform.DLL(Using C++)

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.

EIQ User Transform SDK Files

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.

Compiler Setup

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.

Modifying the EIQ User Transform DLL Code

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.

Building the EIQ User Transform DLL

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.

 

Defining and Using Transforms Created by Perl or Other Scripts

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

 

 

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.