Ingres and OpenAPI
sabato 31 Maggio 2008
I’d the (nsg, IMHO) opportunity to work with the Ingres Database from a C++ program.
Since I don’t like SQL as C embedded, I choose to use the OpenAPI Libraries that comes from the Ingres Distribution on my Etch. They sell the OpenAPI as an “alternative to ODBC”. They are database aware. I’ve to test this. I’ve only used OpenAPI to access a remote Ingres DB. In order to have things working, first of all you’ve to load the environment, located in
Since I don’t like SQL as C embedded, I choose to use the OpenAPI Libraries that comes from the Ingres Distribution on my Etch. They sell the OpenAPI as an “alternative to ODBC”. They are database aware. I’ve to test this. I’ve only used OpenAPI to access a remote Ingres DB. In order to have things working, first of all you’ve to load the environment, located in
# to have some logs of the OpenAPI export IIAPI_TRACE=1 export IIAPI_LOG=/tmp/massi.log #env . /opt/Ingres/IngresII/.ingIIshThen you’ve to go to use the netutil program to add a so called Vnode (a name like cochise::massi, in Ingres terminology) that is an alias for the database/host. On the other part, each OpenAPI function are equals: they need a structure before the function call (called parameter block) that you’ve to fill with all the parameters. It makes an huge use of functions pointers as Callbacks. My working pre is:
/* doInsertIngres()
*
* Vera e propria implementazione della insert in Ingres()
*/
void
LulliServer::doInsertIngres(ServerSocket& s,
string data, string host, string dbname)
{
lm.append_msg("In LulliServer::doInsertIngres()",INFO,__FILE__,__LINE__);
char *dbname_char;
char *vnode_char;
char *ctx_string;
char *query_char;
const string ack="ACK\n";
dbname_char = (char *)malloc(dbname.length());
sprintf(dbname_char, "%s",dbname.c_str());
vnode_char = (char *)malloc(host.length());
sprintf(vnode_char, "%s",host.c_str());
ctx_string=(char *)malloc(dbname.length()+host.length()+4);
sprintf(ctx_string, "%s::%s", vnode_char, dbname_char);
string query;
s << ack;
s >> query;
II_PTR connHandle = (II_PTR)NULL;
II_PTR tranHandle = (II_PTR)NULL;
IIAPI_COMMITPARM commitParm;
// II_PTR stmtHandle;
// IIAPI_QUERYPARM queryParm;
// IIAPI_SETDESCRPARM setDescrParm;
// IIAPI_PUTPARMPARM putParmParm;
// IIAPI_GETQINFOPARM getQInfoParm;
// IIAPI_CLOSEPARM closeParm;
IIAPI_WAITPARM waitParm = { -1 };
IIdemo_init();
IIdemo_conn(ctx_string,&connHandle);
/*
** Valid query: no row count
*/
query_char = (char *)malloc(query.length());
sprintf(query_char, "%s",query.c_str());
fprintf(stderr, "Connecting to %s with sql: %s\n",ctx_string,query_char);
IIdemo_query(&connHandle, &tranHandle,"doing insert",query_char); // leggi 1-7
commitParm.cm_genParm.gp_callback = NULL;
commitParm.cm_genParm.gp_closure = NULL;
commitParm.cm_tranHandle = tranHandle;
IIapi_commit( &commitParm );
while( commitParm.cm_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
if (dbError == true)
IIdemo_rollback(&tranHandle);
IIdemo_disconn(&connHandle);
IIdemo_term();
}
/*
** Name: IIdemo_query
**
** Description:
** Execute SQL statement taking no parameters and returning no rows.
**
** Input:
** connHandle Connection handle.
** tranHandle Transaction handle.
** desc Query description.
** queryText SQL query text.
**
** Output:
** connHandle Connection handle.
** tranHandle Transaction handle.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_query( II_PTR *connHandle, II_PTR *tranHandle,
char *desc, char *queryText )
{
lm.append_msg("In LulliServer::IIdemo_query()",INFO,__FILE__,__LINE__);
IIAPI_QUERYPARM queryParm;
IIAPI_GETQINFOPARM getQInfoParm;
IIAPI_CLOSEPARM closeParm;
IIAPI_WAITPARM waitParm = { -1 };
// printf( "IIdemo_query: %s\n", desc );
/*
** Call IIapi_query to execute statement.
*/
queryParm.qy_genParm.gp_callback = NULL;
queryParm.qy_genParm.gp_closure = NULL;
queryParm.qy_connHandle = *connHandle;
queryParm.qy_queryType = IIAPI_QT_QUERY;
queryParm.qy_queryText = queryText;
queryParm.qy_parameters = FALSE;
queryParm.qy_tranHandle = *tranHandle;
queryParm.qy_stmtHandle = NULL;
IIapi_query( &queryParm );
while( queryParm.qy_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
if ( queryParm.qy_genParm.gp_status != IIAPI_ST_SUCCESS)
IIdemo_checkError(& queryParm.qy_genParm);
/*
** Return transaction handle.
*/
*tranHandle = queryParm.qy_tranHandle;
/*
** Call IIapi_getQueryInfo() to get results.
*/
getQInfoParm.gq_genParm.gp_callback = NULL;
getQInfoParm.gq_genParm.gp_closure = NULL;
getQInfoParm.gq_stmtHandle = queryParm.qy_stmtHandle;
IIapi_getQueryInfo( &getQInfoParm );
while( getQInfoParm.gq_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
if ( getQInfoParm.gq_genParm.gp_status != IIAPI_ST_SUCCESS )
IIdemo_checkError( &getQInfoParm.gq_genParm );
else
IIdemo_checkQInfo( &getQInfoParm );
/*
** Call IIapi_close() to release resources.
*/
closeParm.cl_genParm.gp_callback = NULL;
closeParm.cl_genParm.gp_closure = NULL;
closeParm.cl_stmtHandle = queryParm.qy_stmtHandle;
IIapi_close( &closeParm );
while( closeParm.cl_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
if ( closeParm.cl_genParm.gp_status != IIAPI_ST_SUCCESS )
IIdemo_checkError(&closeParm.cl_genParm);
return;
}
/*
** Name: IIdemo_checkError
**
** Description:
** Check the status of an API function call
** and process error information.
**
** Input:
** genParm API generic parameters.
**
** Output:
** None.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_checkError( IIAPI_GENPARM *genParm )
{
lm.append_msg("In LulliServer::IIdemo_checkError()",INFO,__FILE__,__LINE__);
IIAPI_GETEINFOPARM getErrParm;
char type[33];
char *errorstr;
char *dberrorstr;
/*
** Check API call status.
*/
dberrorstr = (char *)calloc(512,1);
sprintf( dberrorstr, "\tgp_status = %s\n",
(genParm->gp_status == IIAPI_ST_SUCCESS) ?
"IIAPI_ST_SUCCESS" :
(genParm->gp_status == IIAPI_ST_MESSAGE) ?
"IIAPI_ST_MESSAGE" :
(genParm->gp_status == IIAPI_ST_WARNING) ?
"IIAPI_ST_WARNING" :
(genParm->gp_status == IIAPI_ST_NO_DATA) ?
"IIAPI_ST_NO_DATA" :
(genParm->gp_status == IIAPI_ST_ERROR) ?
"IIAPI_ST_ERROR" :
(genParm->gp_status == IIAPI_ST_FAILURE) ?
"IIAPI_ST_FAILURE" :
(genParm->gp_status == IIAPI_ST_NOT_INITIALIZED) ?
"IIAPI_ST_NOT_INITIALIZED" :
(genParm->gp_status == IIAPI_ST_INVALID_HANDLE) ?
"IIAPI_ST_INVALID_HANDLE" :
(genParm->gp_status == IIAPI_ST_OUT_OF_MEMORY) ?
"IIAPI_ST_OUT_OF_MEMORY" :
"(unknown status)" );
lm.append_msg(dberrorstr, ERRO, __FILE__, __LINE__);
dbStatus = dberrorstr;
/*
** Check for error information.
*/
if ( ! genParm->gp_errorHandle ) return;
getErrParm.ge_errorHandle = genParm->gp_errorHandle;
do
{
/*
** Invoke API function call.
*/
IIapi_getErrorInfo( &getErrParm );
/*
** Break out of the loop if no data or failed.
*/
if ( getErrParm.ge_status != IIAPI_ST_SUCCESS )
break;
/*
** Process result.
*/
switch( getErrParm.ge_type )
{
case IIAPI_GE_ERROR :
strcpy( type, "ERROR" ); break;
case IIAPI_GE_WARNING :
strcpy( type, "WARNING" ); break;
case IIAPI_GE_MESSAGE :
strcpy(type, "USER MESSAGE"); break;
default:
sprintf( type, "unknown error type: %d", getErrParm.ge_type);
break;
}
errorstr = (char *)calloc(512,1);
sprintf( errorstr, "\tError Info: %s '%s' 0x%x: %s\n",
type, getErrParm.ge_SQLSTATE, getErrParm.ge_errorPre,
getErrParm.ge_message ? getErrParm.ge_message : "NULL" );
lm.append_msg(errorstr,ERRO,__FILE__,__LINE__);
dbError=true;
} while( 1 );
return;
}
/*
** Name: IIdemo_checkQInfo
**
** Description:
** Processes the information returned by IIapi_getQInfo().
**
** Input:
** getQInfoParm Parameter block from IIapi_getQInfo().
**
** Output:
** None.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_checkQInfo( IIAPI_GETQINFOPARM *getQInfoParm )
{
lm.append_msg("In LulliServer::IIdemo_checkQInfo()",INFO,__FILE__,__LINE__);
/*
** Check query result flags.
*/
if ( getQInfoParm->gq_flags & IIAPI_GQF_FAIL )
printf( "\tflag = IIAPI_GQF_FAIL\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_ALL_UPDATED )
printf( "\tflag = IIAPI_GQF_ALL_UPDATED\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_NULLS_REMOVED )
printf( "\tflag = IIAPI_GQF_NULLS_REMOVED\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_UNKNOWN_REPEAT_QUERY )
printf( "\tflag = IIAPI_GQF_UNKNOWN_REPEAT_QUERY\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_END_OF_DATA )
printf( "\tflag = IIAPI_GQF_END_OF_DATA\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_CONTINUE )
printf( "\tflag = IIAPI_GQF_CONTINUE\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_INVALID_STATEMENT )
printf( "\tflag = IIAPI_GQF_INVALID_STATEMENT\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_TRANSACTION_INACTIVE )
printf( "\tflag = IIAPI_GQF_TRANSACTION_INACTIVE\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_OBJECT_KEY )
printf( "\tflag = IIAPI_GQF_OBJECT_KEY\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_TABLE_KEY )
printf( "\tflag = IIAPI_GQF_TABLE_KEY\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_NEW_EFFECTIVE_USER )
printf( "\tflag = IIAPI_GQF_NEW_EFFECTIVE_USER\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_FLUSH_QUERY_ID )
printf( "\tflag = IIAPI_GQF_FLUSH_QUERY_ID\n" );
if ( getQInfoParm->gq_flags & IIAPI_GQF_ILLEGAL_XACT_STMT )
printf( "\tflag = IIAPI_GQF_ILLEGAL_XACT_STMT\n" );
/*
** Check query result values.
*/
if ( getQInfoParm->gq_mask & IIAPI_GQ_ROW_COUNT )
printf( "\trow count = %d\n", getQInfoParm->gq_rowCount );
if ( getQInfoParm->gq_mask & IIAPI_GQ_CURSOR )
printf( "\treadonly = TRUE\n" );
if ( getQInfoParm->gq_mask & IIAPI_GQ_PROCEDURE_RET )
printf( "\tprocedure return = %d\n", getQInfoParm->gq_procedureReturn );
if ( getQInfoParm->gq_mask & IIAPI_GQ_PROCEDURE_ID )
printf("\tprocedure handle = 0x%x\n",(int)getQInfoParm->gq_procedureHandle);
if ( getQInfoParm->gq_mask & IIAPI_GQ_REPEAT_QUERY_ID )
printf("\trepeat query ID = 0x%x\n",(int)getQInfoParm->gq_repeatQueryHandle);
if ( getQInfoParm->gq_mask & IIAPI_GQ_TABLE_KEY )
printf( "\tReceived table key\n" );
if ( getQInfoParm->gq_mask & IIAPI_GQ_OBJECT_KEY )
printf( "\treceived object key\n" );
return;
}
/*
** Name: IIdemo_init
**
** Description:
** Initialize API access.
**
** Input:
** None.
**
** Output:
** None.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_init()
{
lm.append_msg("In LulliServer::IIdemo_init()",INFO,__FILE__,__LINE__);
IIAPI_INITPARM initParm;
//printf( "IIdemo_init: initializing API\n" );
initParm.in_version = IIAPI_VERSION_1;
initParm.in_timeout = -1;
IIapi_initialize( &initParm );
return;
}
/*
** Name: IIdemo_term
**
** Description:
** Terminate API access.
**
** Input:
** None.
**
** Output:
** None.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_term()
{
lm.append_msg("In LulliServer::IIdemo_term()",INFO,__FILE__,__LINE__);
IIAPI_TERMPARM termParm;
//printf( "IIdemo_term: shutting down API\n" );
IIapi_terminate( &termParm );
return;
}
/*
** Name: IIdemo_conn
**
** Description:
** Open connection with target Database.
**
** Input:
** dbname Database name.
**
** Output:
** connHandle Connection handle.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_conn( char *dbname, II_PTR *connHandle )
{
lm.append_msg("In LulliServer::IIdemo_conn()",INFO,__FILE__,__LINE__);
IIAPI_CONNPARM connParm;
IIAPI_WAITPARM waitParm = { -1 };
//printf( "IIdemo_conn: establishing connection\n" );
connParm.co_genParm.gp_callback = NULL;
connParm.co_genParm.gp_closure = NULL;
connParm.co_target = dbname;
connParm.co_connHandle = NULL;
connParm.co_tranHandle = NULL;
connParm.co_username = NULL;
connParm.co_password = NULL;
connParm.co_timeout = -1;
IIapi_connect( &connParm );
while( connParm.co_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
*connHandle = connParm.co_connHandle;
return;
}
/*
** Name: IIdemo_disconn
**
** Description:
** Release DBMS connection.
**
** Input:
** connHandle Connection handle.
**
** Output:
** connHandle Connection handle.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_disconn( II_PTR *connHandle )
{
lm.append_msg("In LulliServer::IIdemo_disconn()",INFO,__FILE__,__LINE__);
IIAPI_DISCONNPARM disconnParm;
IIAPI_WAITPARM waitParm = { -1 };
//printf( "IIdemo_disconn: releasing connection\n" );
disconnParm.dc_genParm.gp_callback = NULL;
disconnParm.dc_genParm.gp_closure = NULL;
disconnParm.dc_connHandle = *connHandle;
IIapi_disconnect( &disconnParm );
while( disconnParm.dc_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
*connHandle = NULL;
return;
}
/*
** Name: IIdemo_rollback
**
** Description:
** Invokes IIapi_rollback() to rollback current transaction
** and resets the transaction handle.
**
** Input:
** tranHandle Handle of transaction.
**
** Output:
** tranHandle Updated handle.
**
** Return value:
** None.
*/
void
LulliServer::IIdemo_rollback( II_PTR *tranHandle )
{
lm.append_msg("In LulliServer::IIdemo_rollback()",INFO,__FILE__,__LINE__);
IIAPI_ROLLBACKPARM rollbackParm;
IIAPI_WAITPARM waitParm = { -1 };
//printf( "IIdemo_rollback: rolling back transaction\n" );
rollbackParm.rb_genParm.gp_callback = NULL;
rollbackParm.rb_genParm.gp_closure = NULL;
rollbackParm.rb_tranHandle = *tranHandle;
rollbackParm.rb_savePointHandle = NULL;
IIapi_rollback( &rollbackParm );
while( rollbackParm.rb_genParm.gp_completed == FALSE )
IIapi_wait( &waitParm );
*tranHandle = NULL;
return;
}
It is taken from the demo API in the Ingres directory.

