|
A varying-length data structure can hold data whose length varies from one instance to the next. The database server uses the varying-length structure extensively to manage data transfer for DataBlade API modules. This chapter provides the following information about varying-length data structure:
The DataBlade API provides the following data types to support varying-length data.
All these DataBlade API data types have the same underlying structure. For more information about the structure of a varying-length data type, see Creating a Varying-Length Structure.
Tip: The mi_lvarchar data type is not the same as the Illustra mi_varlena data type. The mi_varlena data type is a public structure whose members developers could access. The mi_lvarchar data type is an opaque C structure.
In addition, the mi_varlena data type is a contiguous structure that holds the varying-length data. The mi_lvarchar data type is a varying-length structure, which holds only a pointer to the actual data. For portability of Illustra applications that use mi_varlena, do not access mi_varlena directly. Instead, use the access macros (such as MI_GET_VARLEN and MI_GET_VARDATA), which the DataBlade API maps to the appropriate varying-length accessor functions.
These varying-length data types (mi_lvarchar, mi_bitvarying, mi_sendrecv, mi_impexp, mi_impexpbin, and varying-length opaque types) cannot fit into an MI_DATUM. Therefore, they must be passed by reference to and from C user-defined routines.
All data types, including mi_lvarchar, must be passed by reference within client LIBMI applications.
The following table summarizes the memory operations for a varying-length structure.
Default Memory Duration | Memory Operation | Function Name |
---|---|---|
Current memory duration | Constructor | mi_new_var(), mi_string_to_lvarchar(), mi_var_copy() |
Destructor | mi_var_free() |
This section describes the DataBlade API functions that allocate and deallocate a varying-length structure.
Important: Do not use either the DataBlade API memory-management functions (such as mi_alloc() and mi_free()) or the operating-system memory-management functions (such as malloc() and free()) to handle allocation of varying-length structures.
Creating a Varying-Length Structure
Figure 2-5 lists the DataBlade API functions that create a varying-length structure. These functions are constructor functions for a varying-length structure.
Figure 2-5
The varying-length structure is not contiguous. The allocation functions in Figure 2-5 allocate this structure in two parts:
Important: The varying-length data itself resides in a separate structure; it does not actually reside in the varying-length descriptor.
For example, suppose you call the mi_new_var() function that Figure 2-6 shows.
Figure 2-7 shows the varying-length structure that this mi_new_var() call allocates. This structure consists of both a descriptor and a data portion of 200 bytes. The mi_new_var() function returns a pointer to this structure, which the code in Figure 2-6 assigns to the new_lvarch variable.
The allocation functions in Figure 2-5 on page 2-21 allocate the varying-length structure with the current memory duration. By default, the current memory duration is PER_ROUTINE. For PER_ROUTINE memory, the database server automatically deallocates a varying-length structure at the end of the user-defined routine in which it was allocated. If your varying-length structure requires a longer memory duration, call the mi_switch_mem_duration() function before the call to one of the allocation functions in Figure 2-5 on page 2-21.
The allocation functions in Figure 2-5 on page 2-21 return the newly allocated varying-length structure as a pointer to an mi_lvarchar data type. For example, the call to mi_new_var() in Figure 2-6 on page 2-22 allocates a new mi_lvarchar structure with a data portion of 200 bytes.
To allocate other varying-length data types, cast the mi_lvarchar pointer that the allocation function returns to the appropriate varying-length data type. For example, the following call to mi_new_var() allocates a new mi_sendrecv varying-length structure with a data portion of 30 bytes:
This cast is not strictly required, but many compilers recommend it and it does improve clarity of purpose.
A varying-length structure has a default memory duration of the current memory duration. To conserve resources, use the mi_var_free() function to explicitly deallocate the varying-length structure once your DataBlade API module no longer needs it. The mi_var_free() function is the destructor function for a varying-length structure. It frees both parts of a varying-length structure: the varying-length descriptor and the data portion.
Important: Do not use the DataBlade API memory-management function mi_free() to deallocate a varying-length structure. The mi_free() function does not deallocate both parts of a varying-length structure.
Use mi_var_free() to deallocate varying-length structures that you have allocated with mi_new_var() or mi_var_copy(). Do not use it to deallocate any varying-length structure that the DataBlade API has allocated.
The mi_var_free() function accepts as an argument a pointer to an mi_lvarchar. The following call to mi_var_free() deallocates the mi_lvarchar varying-length structure that Figure 2-6 on page 2-22 allocates:
To deallocate other varying-length data types, cast the mi_lvarchar argument of mi_var_free() to the appropriate varying-length type, as the following code fragment shows:
This cast is not strictly required, but many compilers recommend it and it does improve clarity of purpose.
The varying-length structure contains the following information:
Once you have allocated a varying-length structure, you can access the public members of this structure with the DataBlade API accessor functions in Figure 2-8.
Figure 2-8
Important: To a DataBlade API module, the varying-length structure is an opaque C data structure. Do not access its internal fields directly. Informix does not guarantee that the internal structure of the varying-length structure will not change in future releases. Therefore, to create portable code, always use the accessor functions for this structure to obtain and store values.
Varying-Length Data and Null Termination
When you work with varying-length data, keep the following restrictions in mind:
Instead, always use the data length (which you can obtain with the mi_get_varlen() function) for all operations on varying-length data.
The varying-length accessor functions in Figure 2-8 on page 2-25 do not automatically interpret a null-terminator character. Instead, they transfer the number of bytes that the data length in the varying-length descriptor specifies, as follows:
To convert between null-terminated strings and an mi_lvarchar structure, use the mi_string_to_lvarchar() and mi_lvarchar_to_string() functions. For more information, see DataBlade API Functions for String Conversion.
This section provides the following information about how to store varying-length data:
The mi_set_vardata() and mi_set_vardata_align() functions copy data into an existing data portion of a varying-length structure. These functions assume that the data portion is large enough to hold the data being copied. The code fragment in Figure 2-9 uses mi_set_vardata() to store data in the existing data portion of the varying-length structure that new_lvarch references.
In Figure 2-9, the call to mi_new_var() creates a new varying-length structure and sets the length field to 200. This call also allocates the 200-byte data portion (see Figure 2-7 on page 2-22).
Figure 2-10 shows the format of the varying-length structure that new_lvarch references after the call to mi_set_vardata() successfully completes.
The mi_set_vardata() function copies from the local_var buffer the number of bytes that the data length specifies. Your code must ensure that the data-length field contains the number of bytes you want to copy. In the code fragment in Figure 2-9 on page 2-27, the data-length field was last set by the call to mi_set_varlen() to 110 bytes. However, if the mi_set_varlen() function executed after the mi_set_vardata() call, the data length would still have been 200 bytes (set by mi_new_var()). In this case, mi_set_vardata() would try to copy 200 bytes starting at the location of the local_var variable. Because the actual local_var data only occupies 110 bytes of memory, 90 unused bytes remain in the data portion.
The mi_set_vardata() function aligns the data that it copies on 4-byte boundaries. If this alignment is not appropriate for your varying-length data, use the mi_set_vardata_align() function to store data on a byte boundary that you specify. For example, the following call to mi_set_vardata_align() copies data into the var_struc varying-length structure and aligns this data on 8-byte boundaries:
You can determine the alignment of a data type from its type descriptor with the mi_type_align() function.
Tip: You can also store data in a varying-length structure through the data pointer that you obtain with the mi_get_vardata() or mi_get_vardata_align() function. For more information, see Obtaining the Data Pointer.
The mi_set_vardata_align() function copies the number of bytes that the data-length field specifies.
Storing a Null-Terminated StringThe mi_string_to_lvarchar() function copies a null-terminated string into a varying-length structure that it creates. This function performs the following steps:
The following code fragment uses mi_string_to_lvarchar() to store a null-terminated string in the data portion of a new varying-length structure:
Figure 2-11 shows the format of the varying-length structure that lvarch references after the preceding call to mi_string_to_lvarchar() successfully completes.
The lvarch varying-length structure in Figure 2-11 has a data length of 110. The null terminator is not included in the data length because the mi_string_to_lvarchar() function does not copy the null terminator into the data portion.
If your DataBlade API module needs to store a null terminator as part of the varying-length data, you can take the following steps:
Once you have performed these steps, you can obtain the null terminator as part of the varying-length data.
Important: If you choose to store null terminators as part of your varying-length data, your code must keep track that this data is null-terminated. The DataBlade API functions that handle varying-length structures do not assume the presence of a null terminator.
The following code fragment stores a string plus a null terminator in the varying-length structure that lvarch references:
Figure 2-12 shows the format of this varying-length structure after the preceding call to mi_set_vardata() successfully completes.
Setting the Data Pointer
The mi_set_varptr() function allows you to set the data pointer in a varying-length structure to memory that you allocate. The following code fragment creates an empty varying-length structure, which is a varying-length structure that has no data portion allocated:
Figure 2-13 shows the format of the varying-length structure that new_lvarch references after the fill_buffer() function successfully completes.
The varying-length structure in Figure 2-13 is empty because it has:
Once you have an empty varying-length structure, you can use the mi_set_varptr() function to set the data pointer to the PER_COMMAND memory, as the following code fragment shows:
The preceding call to mi_set_varlen() updates the length in the varying-length structure to the length of 20 bytes. Figure 2-14 shows the format of the varying-length structure that new_lvarch references after the preceding call to mi_set_varptr() successfully completes.
Make sure that you allocate the data-portion buffer with a memory duration appropriate to the use of the data portion.
Use the following DataBlade API accessor functions to obtain information from a varying-length structure.
Varying-Length Information | DataBlade API Accessor Function |
---|---|
Length of varying-length data | mi_get_varlen() |
Data portion | mi_lvarchar_to_string(), mi_var_to_buffer(), mi_var_copy() |
Data pointer | mi_get_vardata(), mi_get_vardata_align() |
The mi_get_varlen() function returns the data length from a varying-length descriptor. Keep in mind the following restrictions about data length:
For the varying-length structure in Figure 2-7 on page 2-22, a call to mi_get_varlen() returns 200. For the varying-length structure that Figure 2-10 on page 2-28 shows, a call to mi_get_varlen() returns 110.
Obtaining Data as a Null-Terminated StringThe mi_lvarchar_to_string() function obtains the data from a varying-length structure and converts it to a null-terminated string. This function performs the following steps:
Suppose you have the varying-length structure that Figure 2-11 on page 2-30 shows. The following code fragment uses the mi_lvarchar_to_string() function to obtain this varying-length data as a null-terminated string:
The code fragment does not need to allocate memory for the var_str string because the mi_lvarchar_to_string() function allocates memory for the new string. After the call to mi_lvarchar_to_string() completes successfully, the var_str variable contains the following null-terminated string:
The mi_var_to_buffer() function copies the data of an existing varying-length structure into a user-allocated buffer. The function copies data up to the data length specified in the varying-length descriptor. You can obtain the current data length with the mi_get_varlen() function.
The following code fragment copies the contents of the varying-length structure in Figure 2-11 on page 2-30 into the my_buffer user-allocated buffer:
After the successful completion of mi_var_to_buffer(), the my_buffer variable points to the following string, which is not null-terminated:
Important: Do not assume that the data in the user-allocated buffer is null-terminated. The mi_var_to_buffer() function does not append a null terminator to the data in the character buffer. Copying Data into a New Varying-Length Structure
The mi_var_copy() function copies data from an existing varying-length structure into a new varying-length structure. This function performs the following steps:
Suppose you have the varying-length structure that Figure 2-11 on page 2-30 shows. The following code fragment uses the mi_var_copy() function to create a copy of this varying-length structure:
After the call to mi_var_copy() completes successfully, the lvarch_copy variable points to a new varying-length structure, as Figure 2-15 shows. The varying-length structure that lvarch_copy references is a completely separate structure from the structure that lvarch references.
Obtaining the Data Pointer
The mi_get_vardata() and mi_get_vardata_align() functions obtain the actual data pointer from the varying-length descriptor. Through this data pointer, you can directly access the varying-length data.
The following code fragment uses the mi_get_vardata() function to obtain the data pointer from the varying-length structure in Figure 2-10 on page 2-28:
Figure 2-16 shows the format of the varying-length structure that new_lvarch references after the preceding call to mi_get_vardata() successfully completes.
You can then access the data through the var_ptr data pointer, as the following code fragment shows:
The database server passes text data to a user-defined routine as an mi_lvarchar structure. Figure 12-3 on page 12-11 shows the implementation of a user-defined function called initial_cap(), which ensures that the first letter of a character string is uppercase and that subsequent letters are lowercase.
The initial_cap() function uses mi_get_vardata() to obtain each character from the data portion of the varying-length structure. This data portion contains the character value that the function receives as an argument. The function checks each letter to ensure that it has the correct case. If the case is incorrect, initial_cap() uses the data pointer to update the appropriate letter. The function then returns a new mi_lvarchar structure that holds the result. For more information, see Handling Character Arguments.
The varying-length structure aligns data on 4-byte boundaries. If this alignment is not appropriate for your varying-length data, use the mi_get_vardata_align() function to obtain the data aligned on a byte boundary that you specify. You can determine the alignment of a data type from its type descriptor with the mi_type_align() function.
Tip: When you obtain aligned data from a varying-length structure that is associated with an extended data type, specify an alignment value to mi_get_vardata_align() that is appropriate for the extended data type. For more information, see Memory Alignment.
The mi_get_vardata_align() function obtains the number of bytes that the data-length field specifies.