Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Implementation Details: Late Binding (DATA AT EXECUTE)

ODBC provides the possibility to provide data for input parameters at execution time, and this feature is especially used for transferring large objects into the database.

Here, the indicator of a host variable signals that the data is available at execution time.

If at least one of these parameters is found, instead of consisting of a single call to execute() or executeBatch, the execution of a prepared statement proceeds according to the following sequence:

  1. Call execute(), it will return IFR_NEED_DATA.
  2. Call nextParameter(index, address). Here, index and address will be filled with the next parameter's details. The address here is set according to the parameter binding, the binding type, and the position in the row array, if batch execution is done. If the method returns IFR_OK, you are finished, if it returns IFR_NEED_DATA,
  3. Call putData(data, lengthindicator) to actually provide the data. Take care that for integral data types, and the speciall NULL and DEFAULT values the data must be delivered in one call, otherwise subsequent calls of putData append to the data. Continue with this step until all data for that parameter has been transferred.
  4. Continue with step 2 until finished.

Internal Execution Sequence
The calling sequence described above is translated into one EXECUTE message, and if necessary, one or more PUTVAL messages.

For doing this, the following measures are taken:

  1. The parameters which are 'normal' bound are converted and inserted into the message. If they are of LONG types, it is kept whether the long data did fit into the message, or was truncated.
  2. All non-LONG parameters which have late binding are collected, converted and inserted.
  3. If the LONG parameters that were not bound with late binding already did not fit, now the EXECUTE message is sent, and if necessary, subsequent PUTVAL messages.
  4. The LONG parameters that were bound with late binding are collected, and inserted, hereby sending a PUTVAL message each time the space in the request packet is filled up.

The following example illustrates the behaviour:

Consider a table TESTDATA defined as follows:

  CREATE TABLE TESTDATA(A INTEGER,
                        B CHAR(200),
                        C LONG BYTE,
                        D CHAR(30),
                        E LONG BYTE)

Assume an INSERT statement on this table, where the parameters for
column C and D are bound having an indicator value DATA AT EXECUTE,
and E is bound to an array of 1000 bytes. We assume also that the
order in the data part is A,B,C,D,E, for the ease of description.

The packet is filled as follows:

(1) execute

    The execute step does check whether there is DATA AT EXECUTE,
    and so returns almost immediately.

(2) nextParameter

    The execute step puts the parse id part into the segment, and then 
    all available data. The segment will then look as follows:

    +----------------+
    | ParseID Part   |
    +----------------+
    | Data Part      |   
    | A              |
    | B              |
    | C (Descriptor) |  <== Descriptor is set to 'no data' for now.
    |                |  <== Space for D is kept, but not filled with data.
    | E (Descriptor) |  <== Points to the data, has flag vm_alldata
    | E (Data)       |      to show there is no more data.
    +----------------+

    Furthermore, the internal structures are laid out, and all DATA AT EXECUTE
    parameters are recorded.

    Finally, the function returns pointing to D, as it is not a LONG column, 
    and non-LONGs are preferred.

(3) putData

    The application fills up D using putData, which fills up the value, 
    and eventually returns IFR_DATA_TRUNC when too much data is inserted.

    Now the segment looks like this:

    +----------------+
    | ParseID Part   |
    +----------------+
    | Data Part      |   
    | A              |
    | B              |
    | C (Descriptor) |  
    | D              | 
    | E (Descriptor) |  
    | E (Data)       |  
    +----------------+

(4) nextParameter

    The next call to this method returns parameter C, and does not
    send any packet - or change anything, as it is not filled up.

(5) putData

    Subsequently, C will be filled with data. At some point, the
    segment will look like:

    +----------------+
    | ParseID Part   |
    +----------------+
    | Data Part      |   
    | A              |
    | B              |
    | C (Descriptor) |  
    | D              | 
    | E (Descriptor) |  
    | E (Data)       |  
    | D (Data)       |  
    +----------------+

    and the packet is filled up completely. Then the packet is sent,
    and normal PUTVAL packets for this LONG are created, which are
    sent when they are filled up (which may happen in extreme even
    several times with one putData.

Special Handling for Batch Execution
When DATA AT EXECUTE is spotted during an executeBatch() operation, the control flow is similar to the case when this happen during execute().

The address returned by the nextParameter call will indicate the row, as it would point to the place where the data would be normally expected, if no DATA AT EXECUTE would be present.

In contrast to a single execute, the data from the rows accumulates in the packet until the packet is full.