123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
- <sect1 id="BEGINCplus_Structure">
- <title>BEGINC++ Structure<indexterm>
- <primary>BEGINC++ Structure</primary>
- </indexterm></title>
- <para><emphasis>resulttype funcname </emphasis><emphasis
- role="bold">(</emphasis><emphasis> parameterlist </emphasis><emphasis
- role="bold">) := BEGINC++<indexterm>
- <primary>BEGINC++</primary>
- </indexterm></emphasis><emphasis role="bold">
- </emphasis><emphasis></emphasis></para>
- <para><emphasis> code</emphasis><emphasis role="bold"> </emphasis></para>
- <para><emphasis role="bold">ENDC++<indexterm>
- <primary>ENDC++</primary>
- </indexterm>;</emphasis></para>
- <informaltable colsep="1" frame="all" rowsep="1">
- <tgroup cols="2">
- <colspec align="left" colwidth="122.40pt" />
- <colspec />
- <tbody>
- <row>
- <entry><emphasis>resulttype</emphasis></entry>
- <entry>The ECL return value type of the C++ function.</entry>
- </row>
- <row>
- <entry><emphasis>funcname</emphasis></entry>
- <entry><para>The ECL definition name of the function.</para></entry>
- </row>
- <row>
- <entry><emphasis>parameterlist</emphasis></entry>
- <entry>A comma separated list of the parameters to pass to the
- <emphasis>function</emphasis>.</entry>
- </row>
- <row>
- <entry><emphasis>code</emphasis></entry>
- <entry>The C++ function source code.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>The <emphasis role="bold">BEGINC++ </emphasis>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 <emphasis role="bold">External
- Service Implementation</emphasis> discussion).</para>
- <para>The implementation must be written to be thread safe and any calls to
- external libraries must be made to thread safe versions of those
- libraries.</para>
- <para><emphasis role="bold">WARNING: This feature could create memory
- corruption and/or security issues, so great care and forethought are
- advised—consult with Technical Support before using.</emphasis></para>
- <sect2 id="ECL_to_Cplus_Mapping">
- <title>ECL to C++ Mapping</title>
- <para>Types are passed as follows:</para>
- <programlisting>//The following typedefs are used below:
- typedef unsigned size32_t;
- typedef wchar_t UChar; [ unsigned short in linux ]</programlisting>
- <para>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).</para>
- <programlisting><emphasis role="bold">ECL C++ [Linux in brackets]</emphasis>
- BOOOLEAN xyz bool xyz
- INTEGER1 xyz signed char xyz
- INTEGER2 xyz int16_t xyz
- INTEGER4 xyz int32_t xyz
- INTEGER8 xyz signed __int64 xyz [ long long ]
- UNSIGNED1 xyz unsigned char xyz
- UNSIGNED2 xyz uint16_t xyz
- UNSIGNED4 xyz uint32_t 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</programlisting>
- <para>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):</para>
- <programlisting>STRING ABC -> size32_t lenAbc, const char * abc;
- UNICODE ABC -> size32_t lenABC, const UChar * abc;</programlisting>
- <para>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:</para>
- <programlisting>DATASET(r) ABC -> size32_t lenAbc, const void * abc
- The rows are accessed as x+0, x + length(row1), x + length(row1) + length(row2)
- LINKCOUNTED DATASET(r) ABC -> size32_t countAbc, const byte * * abc
- The rows are accessed as x[0], x[1], x[2]
- </programlisting>
- <para>NOTE: variable length strings within a record are stored as a 4 byte
- number of characters, followed by the string data.</para>
- <para>Sets are passed as a set of parameters (all, size, pointer):</para>
- <programlisting>SET OF UNSIGNED4 ABC -> bool isAllAbc, size32_t lenAbc, const void * abc</programlisting>
- <para>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:</para>
- <programlisting><emphasis role="bold">ECL C++ [Linux in brackets]</emphasis>
- DATA xyz size32_t & __lenResult, void * & __result
- STRING xyz size32_t & __lenResult, char * & __result
- CONST STRING xyz size32_t lenXyz, const char * xyz
- QSTRING xyz size32_t & __lenResult, char * & __result
- UNICODE xyz size32_t & __lenResult, UChar * & __result
- CONST UNICODE xyz size32_t & __lenResult, const 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
- DATASET(r) size32_t & __lenResult, void * & __result
- LINKCOUNTED DATASET(r)
- size32_t & __countResult, byte * * & __result
- STREAMED DATASET(r)
- returns a pointer to an IRowStream interface
- (see the eclhelper.hpp include file for the definition)</programlisting>
- <para>For example,</para>
- <programlisting>STRING process(STRING value, INTEGER4 len)</programlisting>
- <para>has the prototype:</para>
- <programlisting>void process(size32_t & __lenResult, char * & __result,
- size32_t lenValue, char * value, int len);</programlisting>
- <para>A function that takes a string parameter should also have the type
- prefixed by <emphasis role="bold">const</emphasis> in the ECL code so that
- modern compilers don't report errors when constant strings are passed to
- the function.</para>
- <programlisting>BOOLEAN isUpper(const string mystring) := BEGINC++
- size_t i=0;
- while (i < lenMystring)
- {
- if (!isupper((byte)mystring[i]))
- return false;
- i++;
- }
- return true;
- ENDC++;
- isUpper('JIM');
- </programlisting>
- </sect2>
- <sect2 id="BeginCPP_Available_Options">
- <title>Available Options</title>
- <informaltable colsep="1" frame="all" rowsep="1">
- <tgroup cols="2">
- <colspec align="left" colwidth="122.40pt" />
- <colspec />
- <tbody>
- <row>
- <entry><emphasis role="bold">#option pure</emphasis></entry>
- <entry>By 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++ <emphasis>code</emphasis> causes it
- to be treated as a pure function without side effects.</entry>
- </row>
- <row>
- <entry><emphasis role="bold">#option once</emphasis></entry>
- <entry>Indicates 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.</entry>
- </row>
- <row>
- <entry><emphasis role="bold">#option action</emphasis></entry>
- <entry>Indicates side effects, requiring the optimizer to keep all
- calls to the function.</entry>
- </row>
- <row>
- <entry><emphasis role="bold">#body</emphasis></entry>
- <entry>Delimits the beginning of executable code. All
- <emphasis>code</emphasis> that precedes #body (such as #include)
- is generated outside the function definition; all code that
- follows it is generated inside the function definition.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>Example:</para>
- <programlisting>//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++;
- //examples of embedded, LINKCOUNTED, and STREAMED DATASETs
- inRec := { unsigned id };
- doneRec := { unsigned4 execid };
- out1rec := { unsigned id; };
- out2rec := { real id; };
- DATASET(doneRec) doSomethingNasty(DATASET(inRec) input) := BEGINC++
- __lenResult = 4;
- __result = rtlMalloc(8);
- *(unsigned *)__result = 91823;
- ENDC++;
- DATASET(out1Rec) extractResult1(doneRec done) := BEGINC++
- const unsigned id = *(unsigned *)done;
- const unsigned cnt = 10;
- __lenResult = cnt * sizeof(unsigned __int64);
- __result = rtlMalloc(__lenResult);
- for (unsigned i=0; i < cnt; i++)
- ((unsigned __int64 *)__result)[i] = id + i + 1;
- ENDC++;
- LINKCOUNTED DATASET(out2Rec) extractResult2(doneRec done) := BEGINC++
- const unsigned id = *(unsigned *)done;
- const unsigned cnt = 10;
- __countResult = cnt;
- __result = _resultAllocator->createRowset(cnt);
- for (unsigned i=0; i < cnt; i++)
- {
- size32_t allocSize;
- void * row = _resultAllocator->createRow(allocSize);
- *(double *)row = id + i + 1;
- __result[i] = (byte *)_resultAllocator->finalizeRow(allocSize, row, allocSize);
- }
- ENDC++;
- STREAMED DATASET(out1Rec) extractResult3(doneRec done) := BEGINC++
- class myStream : public IRowStream, public RtlCInterface
- {
- public:
- myStream(IEngineRowAllocator * _allocator, unsigned _id) : allocator(_allocator), id(_id), idx(0) {}
- RTLIMPLEMENT_IINTERFACE
- virtual const void *nextRow()
- {
- if (idx >= 10)
- return NULL;
- size32_t allocSize;
- void * row = allocator->createRow(allocSize);
- *(unsigned __int64 *)row = id + ++idx;
- return allocator->finalizeRow(allocSize, row, allocSize);
- }
- virtual void stop() {}
- private:
- unsigned id;
- unsigned idx;
- Linked<IEngineRowAllocator> allocator;
- };
- #body
- const unsigned id = *(unsigned *)done;
- return new myStream(_resultAllocator, id);
- ENDC++;
- ds := DATASET([1,2,3,4], inRec);
- processed := doSomethingNasty(ds);
- out1 := NORMALIZE(processed, extractResult1(LEFT), TRANSFORM(RIGHT));
- out2 := NORMALIZE(processed, extractResult2(LEFT), TRANSFORM(RIGHT));
- out3 := NORMALIZE(processed, extractResult3(LEFT), TRANSFORM(RIGHT));
- SEQUENTIAL(OUTPUT(out1),OUTPUT(out2),OUTPUT(out3));
- </programlisting>
- <para>See Also: <link linkend="External_Service_Implementation">External
- Service Implementation</link>, <link linkend="EMBED_Structure">EMBED
- Structure</link></para>
- </sect2>
- </sect1>
|