OLE automation routines in BASIC and C++

You can implement OLE automation routines in any language. This section shows you how to implement OLE automation routines using BASIC or C++ as two sample languages.

The following table shows the mapping of OLE automation types to data types in BASIC and C++.

Table 1. Mapping of SQL and OLE data types to BASIC and C++ data types
SQL Type OLE Automation Type BASIC Type C++ Type
SMALLINT short Integer short
INTEGER long Long long
REAL float Single float
FLOAT or DOUBLE double Double double
DATE, TIME, TIMESTAMP DATE Date DATE
CHAR(n) BSTR String BSTR
CHAR(n) FOR BIT DATA SAFEARRAY[unsigned char] Byte() SAFEARRAY
VARCHAR(n) BSTR String BSTR
VARCHAR(n) FOR BIT DATA SAFEARRAY[unsigned char] Byte() SAFEARRAY
LONG VARCHAR BSTR String BSTR
LONG VARCHAR FOR BIT DATA SAFEARRAY[unsigned char] Byte() SAFEARRAY
BLOB(n) BSTR String BSTR
BLOB(n) FOR BIT DATA SAFEARRAY[unsigned char] Byte() SAFEARRAY
GRAPHIC(n), VARGRAPHIC(n), LONG GRAPHIC, DBCLOB(n) BSTR String BSTR

OLE Automation in BASIC

To implement OLE automation routines in BASIC, you need to use the BASIC data types corresponding to the SQL data types mapped to OLE automation types.

The following declaration example is for the OLE automation UDF bcounter, which is created with the BASIC programming language:
     Public Sub increment(output As Long, _
                          indicator As Integer, _
                          sqlstate As String, _
                          fname As String, _
                          fspecname As String, _
                          sqlmsg As String, _
                          scratchpad() As Byte, _
                          calltype As Long)

OLE Automation in C++

The following declaration example is for the OLE automation UDF increment, which is created with the C++ programming language:
     STDMETHODIMP Ccounter::increment (long   *output,
                                       short  *indicator,
                                       BSTR   *sqlstate,
                                       BSTR   *fname,
                                       BSTR   *fspecname,
                                       BSTR   *sqlmsg,
                                       SAFEARRAY **scratchpad,
                                       long   *calltype );
OLE supports type libraries that describe the properties and methods of OLE automation objects. Exposed objects, properties, and methods are described in the Object Description Language (ODL). The ODL description of the previously shown C++ method is as follows:
     HRESULT increment ([out]    long  *output,
                        [out]    short *indicator,
                        [out]    BSTR  *sqlstate,
                        [in]     BSTR  *fname,
                        [in]     BSTR  *fspecname,
                        [out]    BSTR  *sqlmsg,
                        [in,out] SAFEARRAY (unsigned char) *scratchpad,
                        [in]     long *calltype);

You can use the ODL description to specify whether a parameter is an input ([in]), output ([out]), or input/output ([in,out]) parameter. For an OLE automation routine, the routine input parameters and input indicators are specified as [in] parameters, and routine output parameters and output indicators as [out] parameters. For the routine trailing arguments, sqlstate is an [out] parameter, fname and fspecname are [in] parameters, scratchpad is an [in,out] parameter, and calltype is an [in] parameter.

OLE automation defines the BSTR data type to handle strings. BSTR is defined as a pointer to OLECHAR: typedef OLECHAR *BSTR. For allocating and freeing BSTRs, OLE imposes the rule that the called routine frees a BSTR passed in as a by-reference parameter before routine assigns the parameter a new value. The same rule applies for one-dimensional byte arrays that are received by the called routine as SAFEARRAY**. The following list contains OLE imposed rules on parameters:

  • [in] parameters: The database manager allocates and frees [in] parameters.
  • [out] parameters: The database manager passes in a pointer to NULL. The [out] parameter must be allocated by the routine that is called and is freed by the database manager.
  • [in,out] parameters: The database manager initially allocates [in,out] parameters. They can be freed and reallocated by the routine that is called. As is true for [out] parameters, the database manager frees the final returned parameter.

All other parameters are passed as pointers. The database manager allocates and manages the referenced memory.

OLE automation provides a set of data manipulation functions for dealing with BSTRs and SAFEARRAYs.

The following C++ routine returns the first 5 characters of a CLOB input parameter:

     // UDF DDL: CREATE FUNCTION crunch (CLOB(5k)) RETURNS CHAR(5)
                                                                                
     STDMETHODIMP Cobj::crunch (BSTR *in,          // CLOB(5K)                  
                                BSTR *out,         // CHAR(5)                   
                                short *indicator1,  // input indicator           
                                short *indicator2,  // output indicator          
                                BSTR *sqlstate,    // pointer to NULL           
                                BSTR *fname,       // pointer to function name  
                                BSTR *fspecname,   // pointer to specific name  
                                BSTR *msgtext)     // pointer to NULL           
       {                                                                        
          // Allocate BSTR of 5 characters
          // and copy 5 characters of input parameter
                           
          // out is an [out] parameter of type BSTR, that is, 
          // it is a pointer to NULL and the memory does not have to be freed.
          // Database manager will free the allocated BSTR.
                                                                           
          *out = SysAllocStringLen (*in, 5);                                    
          return NOERROR;                                                       
       };                                                                       

An OLE automation server can be implemented as creatable single-use or creatable multi-use. When an OLE automation server is implemented as creatable single-use, each client (that is, a FENCED process) that connects with the CoGetClassObject function to an OLE automation object uses its own instance of a class factory, and run a new copy of the OLE automation server. When an OLE automation server is implemented as creatable multi-use, many clients connect to the same class factory. In an OLE automation server that is implemented as creatable multi-use, each instantiation of a class factory is supplied by an already running copy of the OLE server. If there are no copies of the OLE server running, a copy is automatically started to supply the class object. The choice between single-use and multi-use OLE automation servers is yours, when you implement your automation server. A single-use server can provide better performance.