BEGINC++ Structure<indexterm> <primary>BEGINC++ Structure</primary> </indexterm> resulttype funcname ( parameterlist ) := BEGINC++ BEGINC++ code ENDC++ ENDC++ ; resulttype The ECL return value type of the C++ function. funcname The ECL attribute name of the function. parameterlist The parameters to pass to the C++ function. code The C++ function source code. The BEGINC++ structure makes it possible to add in-line C++ code to your ECL. This is useful where string or bit processing would be complicated in ECL, and would be more easily done in C++, typically for a one-off use. For more commonly used C++ code, writing a plugin would be a better solution (see the External Service Implementation discussion). WARNING: This feature could create memory corruption and/or security issues, so great care and forethought are advised—consult with Technical Support before using. ECL to C++ Mapping Types are passed as follows: //The following typedefs are used below: typedef unsigned size32_t; typedef wchar_t UChar; [ unsigned short in linux ] The following list describes the mappings from ECL to C++. For embedded C++ the parameters are always converted to lower case, and capitalized in conjunctions (see below). ECL C++ [Linux in brackets] BOOOLEAN xyz bool xyz INTEGER1 xyz signed char xyz INTEGER2 xyz signed short xyz INTEGER4 xyz signed int xyz INTEGER8 xyz signed __int64 xyz [ long long ] UNSIGNED1 xyz unsigned char xyz UNSIGNED2 xyz unsigned short xyz UNSIGNED4 xyz unsigned int xyz UNSIGNED8 xyz unsigned __int64 xyz [ unsigned long long xyz ] REAL4 xyz float xyz REAL/REAL8 xyz double xyz DATA xyz size32_t lenXyz, void * xyz STRING xyz size32_t lenXyz, char * xyz VARSTRING xyz char * xyz; QSTRING xyz size32_t lenXyz, char * xyz UNICODE xyz size32_t lenXyz, UChar * xyz VARUNICODE xyz UChar * xyz DATA<nn> xyz void * xyz STRING<nn> xyz char * xyz QSTRING<nn> xyz char * xyz UNICODE<nn> xyz UChar * xyz SET OF ... xyz bool isAllXyz, size32_t lenXyz, void * xyz Note that strings of unknown length are passed differently from those with a known length. A variable length input string is passed as a number of characters, not the size (i.e. qstring/unicode), followed by a pointer to the data, like this (size32_t is an UNSIGNED4): string ABC -> size32_t lenAbc, const char * abc; unicode ABC -> size32_t lenABC, const UChar * abc; A dataset is passed as a size/pointer pair. The length gives the size of the following dataset in bytes. The same naming convention is used: dataset(r) ABC -> size32_t lenAbc, const void * abc NOTE: variable length strings within a record are stored as a 4 byte number of characters, followed by the string data. Sets are passed as a set of parameters (all, size, pointer): set of unsigned4 ABC -> bool isAllAbc, size32_t lenAbc, const void * abc Return types are handled as C++ functions returning the same types with some exceptions. The exceptions have some extra initial parameters to return the results in: ECL C++ [Linux in brackets] DATA xyz size32_t & __lenResult, void * & __result STRING xyz size32_t & __lenResult, char * & __result QSTRING xyz size32_t & __lenResult, char * & __result UNICODE xyz size32_t & __lenResult, UChar * & __result DATA<nn> xyz void * __result STRING<nn> xyz char * __result QSTRING<nn> xyz char * __result UNICODE<nn> xyz UChar * __result SET OF ... xyz bool __isAllResult, size32_t & __lenResult, void * & __result For example, STRING process(STRING value, INTEGER4 len) has the prototype: void process(size32_t & __lenResult, char * & __result, size32_t lenValue, char * value, int len); Available Options #option pureBy default, embedded C++ functions are assumed to have side-effects, which means the generated code won't be as efficient as it might be since the calls can't be shared. Adding #option pure inside the embedded C++ code causes it to be treated as a pure function without side effects. #option onceIndicates the function has no side effects and is evaluated at query execution time, even if the parameters are constant, allowing the optimizer to make more efficient calls to the function in some cases. #option actionIndicates side effects, requiring the optimizer to keep all calls to the function. #body Delimits the beginning of executable code. All code that precedes #body (such as #include) is generated outside the function definition; all code that follows it is generated inside the function definition. Example: //static int add(int x,int y) { INTEGER4 add(INTEGER4 x, INTEGER4 y) := BEGINC++ #option pure return x + y; ENDC++; OUTPUT(add(10,20)); //static void reverseString(size32_t & __lenResult,char * & __result, // size32_t lenValue,char * value) { STRING reverseString(STRING value) := BEGINC++ size32_t len = lenValue; char * out = (char *)rtlMalloc(len); for (unsigned i= 0; i < len; i++) out[i] = value[len-1-i]; __lenResult = len; __result = out; ENDC++; OUTPUT(reverseString('Kevin')); // This is a function returning an unknown length string via the // special reference parameters __lenResult and __result //this function demonstrates #body, allowing #include to be used BOOLEAN nocaseInList(STRING search, SET OF STRING values) := BEGINC++ #include <string.h> #body if (isAllValues) return true; const byte * cur = (const byte *)values; const byte * end = cur + lenValues; while (cur != end) { unsigned len = *(unsigned *)cur; cur += sizeof(unsigned); if (lenSearch == len && memicmp(search, cur, len) == 0) return true; cur += len; } return false; ENDC++; //and another example, generating a variable number of Xes STRING buildString(INTEGER4 value) := BEGINC++ char * out = (char *)rtlMalloc(value); for (unsigned i= 0; i < value; i++) out[i] = 'X'; __lenResult = value; __result = out; ENDC++; See Also: External Service Implementation