After
a statement is prepared or executed, application can call tbdrv_stmt_returns_rows()
to verify if the prepared/executed statement will return a result set.
If
the prepared and executed statement returns a result set, application can use
the following APIs in sequence to get the metadata of the result set:
tbdrv_get_numcols() // returns the number of columns in
a result set.
tbdrv_get_colspec_ex() // get columns information
as array of TBDRV_COLUMN_SPEC
The
metadata of result set is described by the TBDRV_COLUMN_SPEC structure which is
defined as:
typedef struct {
int iColNum;
// Zero based index of the
column to retrieve information about.
// To get the
total number of columns in the result set, call tbdrv_get_numcols()
int iOLEDBDataType;
// Data type returned via this
column.
// These data
types can be any of the OLE DB DBTYPE_xxxx
values. See OLEDB.H for details
int iNullable;
// See piNullable parameter of tbdrv_get_colspec()
for detail
char szColName[TBDRV_COLUMN_NAME_MAX_LEN+1];
// Buffer to accept the column
name
char szTableName[TBDRV_TABLE_NAME_MAX_LEN+1];
// Buffer to accept the table name
char szSchemaName[TBDRV_SCHEMA_NAME_MAX_LEN+1];
// Buffer to accept the
schema name
char szDBAliasName[TBDRV_EIQ_DB_ALIAS_NAME_MAX_LEN+1];
//Buffer to accept the database alias
name
char szTableAliasName[TBDRV_TABLE_NAME_MAX_LEN+1]; //Buffer to accept the table
alias name.
int iLen; //
Length of the data for this column
int iPrecision; // See
comment in tbdrv_get_colspec()
int iScale;
// Currently unused
int iMantissaPrecision;
// Currently unused
int iMaxExponent;
// Currently
unused
int iAliasLevel; //
Currently unused
int iRowBufferOffset;
// Column
offset in the row buffer which is used the get the pointer to column value
// in result
set buffer specified in tbder_get_rows()
int
iSuperSchemaFlags; //
Internal column flags mask
int
iLOBLocatorType; // Large object locator type - see comments in tbdrv_read_lob_col_by_locator() for details
char
_reserved[92]; //
For future use
}
TBDRV_COLUMN_SPEC;
There
are two ways to fetch data:
Example:
while( tbdrv_fetch_row(lsession, lstatement, &iRowhandle)==SQLDRV_SUCCEED ) // iterate through the result set row by row
for(int
i=0; i<iNumCol; i++) // get column value column
by column where iNumCol is number of column in the
result set.
tbdrv_get_colval() //
piIndicator returns the Length/Indicator; see notes below for details.
The size of single row in bytes for the
result set includes both the size of column values and their length/indicator buffer as illustrated
in the following diagram which shows the layout of row buffers in the result
set generated by the query:
SELECT
A, B, C from sample_table
The
iRowBufferOffset in the TBDRV_COLUMN_SPEC is the 0 based position in the row
buffer for particular column.
To get the pointer to
value of COLUMN B which is the second column:
*pB
= &pRowBuffer[pColSpec[1]. iRowBufferOffset];
To get the length/indicator of COLUMN B:
pBLenorNull
= &(pRowBuffer[pColSpec[1]. iRowBufferOffset + pColSpec[1]. iLen ];
Example:
tbdrv_get_row_buffer_len(lsession,
lstatementm &iRowBufferLen); //
iRowBufferLen is the size of a single row in bytes for the result set.
unsigned
char *pBuffer = new[iRowBufferLen* iRequestedRowCount]; // based on the application requirement and memory usage,
allocate
// memory to hold the
data of the number of rows requested.
while(
SQLDRV_SUCCESS ==
tbdrv_get_rows(lSessionHandle,
lStatementHandle, 1, plRowHandles,
(unsigned char*)pBuffer, iBufferLen*50, &iReturnedRowCount) )
{
char *pRowBuffer = pBuffer; //
pointer to the first row buffer
for(int
r=0; r<iReturnedRowCount; r++) //
process result buffer row by row
{
for(c=0;
c<iNumCols; c++)
// access column
value column by column based on the metadata specified in TBDRV_COLUMN_SPEC
array pColSpec.
{
// Length/Indicator values; see notes below.
int
iSizeOrNullIndicator = *((int*)&pRowBuffer[pColSpec[c]. iRowBufferOffset+
pColSpec[c]. iLen]);
//
get the pointer to data in the row buffer.
unsigned
char* pData = &pRowBuffer[pColSpec[c]. iRowBufferOffset]
.
pRowBuffer
+= iRowBufferLen; // advanced the
pointer to next row by iRowBufferLen bytes
.
.
Length/Indicator Values:
The length/indicator buffer is used to
pass the byte length of the data in the data buffer or a special indicator such
as TBDRV_NULL_DATA, which indicates that the data is NULL.
But for the LOB column, this is the
upper bound of size of LOB data in the current row.
This
value is a 4 bytes singed integer as the output parameter piIndicator
in tbdrv_get_colval().
Binary
Large Object (BLOB) and Character Large Object (CLOB) data is useful in certain situations where
data which does not follow a normal structure needs to be stored an manipulated in a free form.
To
determinate if the result set column is LOB, application can check the
iNullable in TBDRV_COLUMN_SPEC array returned by tbdrv_get_colspec_ex(). The iNullable is a bitmask that
describes column characteristics. If iNullable & DBCOLUMNFLAGS_ISLONG is
true, then the column is a LOB.
The
following APIs provide access to BLOB and CLOB data in single row
fetch.
tbdrv_get_colval()
- returns LOB locator and size in bytes calling application needs to allocate
to retrieve LOB value in one chunk.
tbdrv_read_lob_col_by_locator()
- copies LOB value from data storage to user provided buffer.
Each
of these APIs work with the current row in the context of a statement
handle. The current row is defined as
the row (or rows in a multi-table join) last fetched (via tbdrv_fetch_row()).
..
..
tbdrv_get_colspec_ex(lSessionHandle,
lStatementHandle, iNumCols, pColSpecs, &lNumColReturned); // get column info
while( tbdrv_fetch_row(lSessionHandle,
lStatementHandle, &lRowHandle) == SQLDRV_SUCCESS )
{
for(int i=0;
i< lNumColReturned; i++)
{
unsigned
char *pszVal = new unsigned char[pColSpecs[i].iLen+1];
int
iLen = pColSpecs[i].iLen+1;
int
iXODataType, iIndicator;
if(
SQLDRV_SUCCESS == tbdrv_get_colval(lSessionHandle,
lStatementHandle,
i,
&iXODataType),
&iIndicator, // iIndicator is the size in bytes required to get the LOB value in one
chunk
(void*)pszVal, //
szVal is the LOB locator
&iLen)
{
if(
pColSpecs[i].iNullable & DBCOLUMNFLAGS_ISLONG && stValue.iIndicator
!= TBDRV_NULL_DATA && iIndicator>0 )
// clob, blob, memo, or doc column
{
unsigned char * pLOBBuffer = null;
WtInt32
lBufferLength = iIndicator, lBytesRead =
0, lBytesRequired = 0;
if(pColSpecs[i]. iOLEDBDataType
== DBTYPE_BYTES ) // binary large object
{
pLOBBuffer = new unsigned char[iIndicator];
}
else
{
pLOBBuffer
= new unsigned char[iIndicator+1]; // for CLOB, add one more byte for null
terminated 0
lBufferLength++;
}
WtInt32 iRet = tbdrv_read_lob_col_by_locator( lSessionHandle,
lStatementHandle,
i,
pColSpecs[i].iLOBLocatorType,
iLen,
(unsigned char*)szVal,
lBufferLength,
(WtUChar8*)pLOBBuffer,
&lBytesRead,
&lBytesRequired );
}
}
}
}
..
..
Another
way is to use tbdrv_get_lob_col_length() and
tbdrv_read_lob_col().
Following
is an example code sequence of processing a result set through
SQL SELECT command and
reading the BLOB or CLOB data for each record while traversing the results.
tbdrv_execute_stmt()
while(
tbdrv_fetch_row() )
tbdrv_get_lob_col_length()
tbdrv_read_lob_col()
To
access large object data in bulk fetch mode, use the LOB locators returned by tbdrv_get_rows(). LOB locators are the references to LOB values. When the application passes the locators to the server while
requesting the result, and the server returns the LOB result.
char *pszSQL = "SELECT personid, note from table1";
// where note is a CLOB field.
tbdrv_execute_immed_stmt(lSessionHandle, lStatementHandle,
pszSQL, &iNumRowsAffected); //
execute the statement
tbdrv_get_numcols(lSessionHandle, lStatementHandle,
&iNumCols); // get column count from result
set
TBDRV_COLUMN_SPEC *pColSpecs = new
TBDRV_COLUMN_SPEC[iNumCols];
WtInt32 lRecordsCopied = 0;
tbdrv_get_colspec_ex(lSessionHandle, lStatementHandle,
iNumCols, pColSpecs, &lRecordsCopied);
// get column info
tbdrv_get_row_buffer_len(lSessionHandle,
lStatementHandle, &iBufferLen ); //
get the buffer length for single row
char *pBuffer = new char[iBufferLen*50]; //
allocate enough buffer to hold 50 rows
unsigned int *plRowHandles = new unsigned int[ 50 ] ; // allocate row handles
ZeroMemory( plRowHandles, sizeof(unsigned int) * 50 );
while( SQLDRV_SUCCESS == tbdrv_get_rows(lSessionHandle,
lStatementHandle, 50, plRowHandles,
(unsigned char*)pBuffer, iBufferLen*50, &iReturnedRowCount) )
{
char
*pRowBuffer = pBuffer;
for(j=0;
j<iNumCols; j++)
{
int iIndicator =
*((int*)&pRowBuffer[pColSpecs[j].iRowBufferOffset+pColSpecs[j].iLen]); // size or null indicator
if(
pColSpecs[j].iNullable & DBCOLUMNFLAGS_ISLONG
&& iIndicator != TBDRV_NULL_DATA)
// to
check the column is a LOB and value is not null
{
WtUChar8 *pLOBLocator =
(WtUChar8*)(&pRowBuffer[pColSpecs[j].iRowBufferOffset]); //
pointer to lob locator,
WtInt32
lBytesRead = 0, lBytesRequired = 0;
WtInt32
lBufferLength = iIndicator;
if(pColSpecs[j].iOLEDBDataType
& DBTYPE_STR) lBufferLength++; // one extral byte for terminated null for
CLOB
void*
pLOBBuffer = malloc(lBufferLength);
WtInt32
iRet = tbdrv_read_lob_col_by_locator( lSessionHandle,
lStatementHandle,
j,
pColSpecs[j].iLOBLocatorType,
pColSpecs[j].iLen,
pLOBLocator,
lBufferLength,
(WtUChar8*)
pLOBBuffer, // buffer to hold the LOB
data
&lBytesRead,
// number of byte copied to
the buffer
&lBytesRequired
); // actual size of byte require,
normally, this will be size indicator
.
.
.
}
}
}
To write BLOB or CLOB data via INSERT command or UPDATE command, the application needs to prepare the SQL statement with parameter markers(?).
These
two APIs are useful for setting BLOB and CLOB data:
The
following is an example for setting the BLOB column 'image' and CLOB column 'note' in table
table1. 'personid' is the primary key whose data type is defined as INT through
SQL UPDATE command with parameter
markers(?).
tbdrv_prepare_stmt( lSessionHandle, lStatementHandle,
"update table1 set note = ? , image = ? where personid = ?")
int iNumParams = 0;
tbdrv_get_numparams(lSessionHandle, lStatementHandle,
&iNumParams )
ASSERT(iNumParams==3);
// set
the note and image of the person with
person id 1
tbdrv_init_param(
lSessionHandle, lStatementHandle, 1, 0,
NoteBuffer1, DBTYPE_STR, NoteBufferSize1)
tbdrv_init_param(
lSessionHandle, lStatementHandle, 2, 0,
ImageBuffer1, DBTYPE_BYTES, ImageBufferSize1)
int
personid = 1;
tbdrv_init_param(
lSessionHandle, lStatementHandle, 3, 0,
&personid, DBTYPE_I4, sizeof(int))
tbdrv_execute_stmt()
// set
the note and image of the person with person id 2
tbdrv_init_param(
lSessionHandle, lStatementHandle, 1, 0,
NoteBuffer2, DBTYPE_STR, NoteBufferSize2)
tbdrv_init_param(
lSessionHandle, lStatementHandle, 2, 0,
ImageBuffer2, DBTYPE_BYTES, ImageBufferSize2)
personid
= 2;
tbdrv_init_param(
lSessionHandle, lStatementHandle, 3, 0,
&personid, DBTYPE_I4, sizeof(int))
tbdrv_execute_stmt()
.
.
Copyright © 2019 , WhamTech, Inc. All rights reserved. This
document is provided for information purposes only and the contents hereof are
subject to change without notice. Names may be
trademarks of their respective owners.