The DataBlade API provides a stream I/O interface, which enables you to use the same function calls to access different objects. Stream is a generic term for an object that can be written to or read from. A stream has the following information associated with it:
When you first open a stream, its seek position is at byte zero (0).
To provide access to a stream from within a C UDR, the DataBlade API has the MI_STREAM data type structure for stream descriptors. An MI_STREAM structure contains information about a stream on a particular object. The following table summarizes the memory operations for a stream descriptor.
The stream-open function is the stream I/O function that opens the stream, making the data available for a read or write operation. It returns a pointer to a stream descriptor, which the C UDR uses to access the stream. For more information, see The Stream-Open Function.
Once a particular stream is open, a UDR can use the generic functions of the stream I/O interface to access the associated I/O object. Each of the generic stream I/O functions requires a stream descriptor for the stream on which the function is to operate. The usual sequence of access is to seek to the desired location in the stream, read or write the desired number of bytes, and close the stream.
Table 87 shows the generic stream I/O functions of the DataBlade API. You can use these generic stream I/O functions on any stream (as long as the stream class implements them).
The advantage of accessing data through a stream is that the call to the generic stream I/O function is the same, regardless of the format of the underlying data. With these generic stream-I/O functions, the DataBlade API provides a common interface for the transportation and access of data independent of the data type or destination.
For example, the following call to mi_stream_read( ) reads 164 bytes of data from a stream into a user-defined buffer named buf:
nbytes_read = mi_stream_read(strm_desc, buf, 164);
The calling code does not need to concern itself about the format of the underlying data. Whether mi_stream_read( ) reads the data from a file, character array, varying-length structure, or user-defined stream depends on which stream-open function has obtained the pointer to the stream descriptor (MI_STREAM structure).
In addition to the generic stream I/O functions in Table 87, the stream I/O interface contains the following functions for different stream classes.
Classes of Stream I/O Function | Stream I/O Function | More Information |
---|---|---|
Stream-open functions for the
predefined stream classes: |
Using Predefined Stream Classes | |
|
||
Abstract stream I/O functions for user-defined streams |
Type-specific stream-open function |
Creating a User-Defined Stream Class |
The DataBlade API provides several predefined stream classes that you can access with the stream I/O interface.
The following table shows the predefined stream classes that the DataBlade API provides and their associated stream-open functions.
Predefined Stream Class | Stream-Open Function |
---|---|
File stream | mi_stream_open_fio( ) |
String stream | mi_stream_open_str( ) |
Varying-length-data stream | mi_stream_open_mi_lvarchar( ) |
The mistrmtype.h header file declares these predefined stream-open functions.
Table 87 lists the stream I/O functions that the DataBlade API provides.
For example, the following code fragment reads 26 bytes of data from a string stream into a user-defined buffer named buf:
#define STRING_SIZE = 80 MI_STREAM *strm_desc; mi_integer nbytes; char buf[200]; char string_txt[STRING_SIZE] = "A stream is a generic term for some object that can be\ written to or read from." strm_desc = mi_stream_open_str(NULL, string_txt, STRING_SIZE); if ( (nbytes = mi_stream_read(strm_desc, buf, 26)) != 26 ) /* error in read */ mi_stream_close(strm_desc);
After this code fragment completes, the buf user-defined buffer contains the following character string:
A stream is a generic term
The following sections provide additional details on each of the predefined DataBlade API stream classes.
The file stream provides access to an operating-system file through the stream I/O interface. To support a data stream on an operating-system file, the DataBlade API provides the stream I/O functions in Table 88.
As Table 88 shows, the stream I/O interface for a file stream consists of a type-specific stream-open function, mi_stream_open_fio( ), plus the generic stream I/O functions. The mi_stream_open_fio( ) function opens the file and returns a new file stream.
The other stream I/O functions in Table 88 handle return status differently from DataBlade API file-access functions because the stream I/O functions do not allow you to obtain the errno status value directly. Instead, these functions handle their return status as follows:
The stream I/O function maps the values associated with errno to DataBlade API constants that have negative values. The mistream.h header file defines these constants.
The string stream provides access to a character array through the stream I/O interface. The string stream does not handle character data as null-terminated strings. It does not evaluate the contents of the data stream in any way. To support a data stream on a character array, the DataBlade API provides the stream I/O functions in Table 89.
As Table 89 shows, the stream I/O interface for a string stream consists of the generic stream I/O functions plus a type-specific stream-open function, mi_stream_open_str( ).
The varying-length-data stream provides access to the data within a varying-length structure (mi_lvarchar) through the stream I/O interface. A varying-length-data stream does not handle varying-length data as null-terminated strings. It also does not evaluate the contents of the data stream in any way. To support a data stream on a varying-length structure, the DataBlade API provides the stream I/O functions in Table 90.
As Table 90 shows, the stream I/O interface for a varying-length-data stream consists of the generic stream I/O functions plus a type-specific stream-open function, mi_stream_open_mi_lvarchar( ). This function returns a new varying-length-data stream.
You can provide a stream I/O interface to create your own protocol for reciprocal reading and writing of SQL data and other data streams. The DataBlade API stream I/O interface provides a consistent interface for accessing data; that is, each stream I/O function has a fixed function name and argument list, regardless of the actual kind of stream that it accesses. This fixed syntax provides the main benefits of stream access:
To create a user-defined stream class, you need to write the following stream I/O functions:
Each type of data to which a stream provides access usually has a unique way of being opened. Its stream-open function must accept as arguments the information required to open the data so that the mi_stream_init( ) function can initialize the stream.
You must implement the generic stream I/O functions that your stream supports so that they correctly handle the format of your stream data.
The mi_stream_init( ) function initializes the stream descriptor with the arguments it receives. The following code fragment of a stream-open function calls mi_stream_init( ) with the stream-operations structure in Figure 81, the internal structure for the mytype opaque type, and a NULL-valued pointer:
MI_STREAM *mi_stream_open_mytype(void *mydata) { MI_STREAM *strm_desc; /* could be passed in as input to open( ) * also. */ /* Code to process any stream-open arguments */ ... /* Call to mi_stream_init( ) to allocate and initialize * the stream descriptor */ strm_desc = mi_stream_init(stream_ops_mytype, mydata, NULL); /* Return pointer to newly allocated stream descriptor */ return strm_desc; }
Because mi_stream_init( ) receives a NULL-valued pointer as its stream descriptor, it allocates the stream descriptor in the current memory duration. The mi_stream_init( ) function then returns a pointer to this newly allocated structure, which the mi_stream_open_mytype( ) function also returns.
Your stream-open function must take the following steps:
The stream-open function must prepare the arguments for the call to the mi_stream_init( ) function, which initializes and optionally allocates an MI_STREAM structure. The mi_stream_init( ) function takes the following arguments:
The stream-operations structure contains pointers to the C functions that implement the generic stream I/O functions for the particular stream. A valid stream-operations structure must exist for the DataBlade API to locate at runtime your type-specific implementations of these generic stream I/O functions. Therefore, it must be initialized before the call to mi_stream_init( ).
Figure 80 shows the declaration of the stream-operations structure, mi_st_ops. For the most current definition, see the mistream.h header file.
#define OPS_NAME_LENGTH 40 struct mi_stream_operations { /* the pointers to the functions */ mi_integer (*close)(MI_STREAM *strm_desc); mi_integer (*read)(MI_STREAM *strm_desc, void *buf, mi_integer nbytes); mi_integer (*write)(MI_STREAM *strm_desc, void *buf, mi_integer nbytes); mi_integer (*seek)(MI_STREAM *strm_desc, mi_int8 *offset, mi_integer whence); mi_int8 * (*tell)(MI_STREAM *strm_desc); mi_integer (*setpos)(MI_STREAM *strm_desc, mi_int8 *pos); mi_integer (*getpos)(MI_STREAM *strm_desc, mi_int8 *pos); mi_integer (*length)(MI_STREAM *strm_desc, mi_int8 *length); /* names of the functions above */ char close_name [OPS_NAME_LENGTH]; char read_name [OPS_NAME_LENGTH]; char write_name [OPS_NAME_LENGTH]; char seek_name [OPS_NAME_LENGTH]; char tell_name [OPS_NAME_LENGTH]; char setpos_name[OPS_NAME_LENGTH]; char getpos_name[OPS_NAME_LENGTH]; char length_name[OPS_NAME_LENGTH]; /* the function handles for the functions above */ void *close_fhandle; void *read_fhandle; void *write_fhandle; void *seek_fhandle; void *tell_fhandle; void *setpos_fhandle; void *getpos_fhandle; void *length_fhandle; } mi_st_ops;
As Figure 80 shows, the stream-operations structure consists of the following parts:
You should initialize the pointers and names and set the handles to NULL.
Figure 81 shows a sample stream-operations structure that provides function pointers for the type-specific implementations of the mi_stream_close( ), mi_stream_read( ), and mi_stream_write( ) functions for a stream on a user-defined type named newstream.
static struct mi_st_ops stream_ops_newstream = { stream_close_newstream, stream_read_newstream, stream_write_newstream, NULL, NULL, NULL, NULL, NULL, "stream_close_newstream", "stream_read_newstream", "stream_write_newstream", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
The code fragment in Figure 81 statically initializes the stream-operations structure. If you initialize this structure dynamically, do so in the stream-open function.
The second argument to mi_stream_init( ) is an uninterpreted data pointer that is stored in the MI_STREAM structure initialized by the call to mi_stream_init( ). The stream interface does not interpret this pointer, which is for the benefit of the stream implementer. You can retrieve the value of this pointer through a call to mi_stream_get_dataptr( ).
A stream descriptor holds information about the stream that all stream I/O functions need to access. The mi_stream_init( ) function accepts as its stream-descriptor argument either of the following values:
When you pass the mi_stream_init( ) function a NULL-valued pointer for its stream-descriptor argument, the function allocates a new stream descriptor in the current memory duration. If your application requires a specific memory duration for the stream descriptor, your stream-open function can perform one of the following tasks:
The mi_switch_mem_duration( ) function changes the current memory duration. Its return value is the previous current duration so that you can return the duration to its original value. For more information, see Changing the Memory Duration.
In this case, pass a NULL-valued pointer as the stream descriptor to mi_stream_init( ) so that mi_stream_init( ) allocates a new stream descriptor in the new current memory duration.
In this case, pass a pointer to the allocated stream descriptor as the stream descriptor for mi_stream_init( ) so that this function does not allocate a new stream descriptor. The mi_stream_close( ) function does not automatically free a stream descriptor that your stream-open function allocates. Your code must handle the deallocation.
After your type-specific stream-open function has prepared the arguments for the mi_stream_init( ) function, it must call mi_stream_init( ) to initialize the stream descriptor.
The stream descriptor, MI_STREAM, holds information about the data stream such as the data and its seek position. For the most current definition of the MI_STREAM structure, see the mistream.h header file.
To provide access to the data in your user-defined stream, you must implement the appropriate generic stream I/O functions. The following table shows which stream I/O functions to implement for the stream characteristics that your stream supports.
Consider the following information when deciding which stream I/O functions to implement:
If your stream is to be read-only, you need to implement the mi_stream_read( ) function but not the mi_stream_write( ) function. For a write-only stream, implement only the mi_stream_write( ) function. For a read/write stream, implement both mi_stream_read( ) and mi_stream_write( ).
If your stream supports a seek position, you must maintain the st_pos field of the stream descriptor. You can choose whether to support one or two methods of accessing the stream seek position:
The mi_stream_tell( ) function returns the current stream seek position as its return value. This function cannot return any negative error value to indicate the cause of an error.
The mi_stream_setpos( ) function returns the current stream seek position as one of its parameters. This function can return an integer status value.
If your stream does not have a seek position, you do not need to write any of the following functions: mi_stream_seek( ), mi_stream_tell( ), mi_stream_getpos( ), or mi_stream_setpos( ).
The type-specific implementation of mi_stream_close( ) must explicitly free any memory that the associated stream-open function (or any other of the generic stream I/O functions) has allocated. For information, see Releasing Stream Resources.
The following general rules apply to values that the generic stream I/O functions return:
To declare a stream as an argument or return value of a C UDR, use the MI_STREAM data type. When you register this UDR in the database, use the opaque data type stream to represent the stream descriptor.
The database server represents a stream with the stream opaque type. As for other opaque types, the database server stores information on stream in the sysxtdtypes system catalog table.
For example, suppose you have a C declaration for a UDR named get_data( ):
mi_lvarchar *get_data(strm_desc, nbytes) MI_STREAM *strm_desc; mi_integer nbytes;
The following CREATE FUNCTION statement registers the get_data( ) UDR, using the stream data type as its first argument:
CREATE FUNCTION get_data(data_source stream, nbytes INTEGER) RETURNS VARCHAR EXTERNAL NAME '/usr/local/udrs/stream/stream.so(get_data)' LANGUAGE C;
When your DataBlade API module no longer needs a stream, you need to assess whether you can release resources that the stream is using. A stream descriptor that the mi_stream_init( ) function allocated has the current memory duration, so it remains valid until one of the following events occurs:
To conserve resources, use the mi_stream_close( ) function to deallocate the stream descriptor explicitly when your DataBlade API module no longer needs it. The mi_stream_close( ) function is the destructor function for a stream descriptor. This function frees a stream descriptor that mi_stream_init( ) allocated and any associated resources, including the stream-data buffer.
The mi_stream_close( ) function does not automatically free a stream descriptor allocated by your stream-open function. If the mi_stream_init( ) function does not allocate a stream descriptor, your type-specific implementation of mi_stream_close( ) must handle the deallocation.
Enterprise Edition Home | Express Edition Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]