odbtpcli.c
/*
ODBTPCLI is a general purpose ODBTP client that demonstrates how
to execute a query and fetch rows if the query generates a result
set. ODBTPCLI requires a file containing 3 or more lines of the
following format to be specified on the command line when running
the program.
Line 1: Hostname of ODBTP server
Line 2: ODBC connect string
Line 3: Line 1 of SQL query
.
.
.
Line N: Line N - 2 of SQL query
Example file contents:
odbtp.somewhere.com
DRIVER={SQL Server};SERVER=sqlsrvr;UID=myuid;PWD=mypwd;DATABASE=master;
EXEC sp_who
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "odbtp.h"
odbBOOL FetchRows( odbHANDLE hQry, odbUSHORT usTotalCols );
void RightTrim( odbPSTR pszText );
void PrintTextData( odbPCSTR pszText, odbLONG lLen );
void PrintBinaryData( odbPBYTE pbyData, odbLONG lLen );
int main( int argc, char* argv[] )
{
odbHANDLE hCon;
FILE* file;
odbHANDLE hQry;
odbLONG l;
odbPSTR psz;
odbCHAR szDbConnect[256];
odbCHAR szServer[128];
odbCHAR szSQL[0x20000];
odbUSHORT usCol, usTotalCols;
odbUSHORT usLoginType = ODB_LOGIN_NORMAL;
odbWinsockStartup(); /* Only required for Win32 clients. */
if( argc < 2 ) {
fprintf( stderr, "Syntax: odbtpcli connect_file\n" );
return 1;
}
if( !(file = fopen( argv[1], "r" )) ) {
fprintf( stderr, "Unable to open %s\n", argv[1] );
return 1;
}
if( !fgets( szServer, sizeof(szServer), file ) ) {
fprintf( stderr, "Unable to read file %s\n", argv[1] );
fclose( file );
return 1;
}
if( !fgets( szDbConnect, sizeof(szDbConnect), file ) ) {
fprintf( stderr, "Unable to read file %s\n", argv[1] );
fclose( file );
return 1;
}
psz = szSQL;
l = sizeof(szSQL);
for( fgets( psz, l, file ); !feof( file ); fgets( psz, l, file ) ) {
l -= strlen(psz);
psz += strlen(psz);
}
*psz = 0;
fclose( file );
RightTrim( szServer );
RightTrim( szDbConnect );
RightTrim( szSQL );
if( !(hCon = odbAllocate(NULL)) ) {
fprintf( stderr, "Unable to allocate\n" );
return 1;
}
if( !odbLogin( hCon, szServer, 2799, usLoginType, szDbConnect ) ) {
fprintf( stderr, "Login Failed: %s\n", odbGetErrorText( hCon ) );
odbFree( hCon );
return 1;
}
fprintf( stderr, "Version: %s\n\n", odbGetVersion( hCon ) );
if( !odbSetAttrLong( hCon, ODB_ATTR_FULLCOLINFO, 1 ) ) {
fprintf( stderr, "Set Attribute failed: %s\n", odbGetErrorText( hCon ) );
odbLogout( hCon, TRUE );
odbFree( hCon );
return 1;
}
if( !(hQry = odbAllocate( hCon )) ) {
fprintf( stderr, "Qry Alloc Failed: %s\n", odbGetErrorText( hCon ) );
odbLogout( hCon, TRUE );
odbFree( hCon );
return 1;
}
if( !odbExecute( hQry, szSQL ) ) {
fprintf( stderr, "Execute Failed: %s\n", odbGetErrorText( hQry ) );
odbLogout( hCon, TRUE );
odbFree( hCon );
return 1;
}
while( !odbNoData( hQry ) ) {
if( (usTotalCols = odbGetTotalCols( hQry )) > 0 ) {
for( usCol = 1, l = 1; usCol <= usTotalCols; usCol++ ) {
if( usCol > 1 ) printf( "," );
psz = (odbPSTR)odbColName( hQry, usCol );
if( *psz )
PrintTextData( psz, -1 );
else
printf( "\"computed%d\"", l++ );
}
printf( "\n" );
if( !FetchRows( hQry, usTotalCols ) ) {
fprintf( stderr, "FetchRows Failed: %s\n", odbGetErrorText( hQry ) );
odbLogout( hCon, TRUE );
odbFree( hCon );
return 1;
}
}
else if( odbGetResponseCode( hQry ) == ODBTP_ROWCOUNT ) {
printf( "%i rows affected.\n", odbGetRowCount( hQry ) );
}
else {
printf( "MESSAGE: %s\n", odbGetResponse( hQry ) );
}
if( !odbFetchNextResult( hQry ) ) {
fprintf( stderr, "FetchNextResult Failed: %s\n", odbGetErrorText( hQry ) );
odbLogout( hCon, TRUE );
odbFree( hCon );
return 1;
}
else if( !odbNoData( hQry ) ) {
printf( "<<<NEXT RESULT>>>\n" );
}
}
if( !odbLogout( hCon, usLoginType == ODB_LOGIN_RESERVED ) ) {
fprintf( stderr, "Logut Error: %s\n", odbGetErrorText( hCon ) );
odbFree( hCon );
return 1;
}
odbFree( hCon );
odbWinsockCleanup(); /* Only required for Win32 clients. */
return 0;
}
odbBOOL FetchRows( odbHANDLE hQry, odbUSHORT usTotalCols )
{
odbBOOL bOK;
odbPVOID pData;
odbPTIMESTAMP pts;
odbCHAR sz[32];
odbUSHORT usCol;
while( (bOK = odbFetchRow( hQry )) && !odbNoData( hQry ) ) {
for( usCol = 1; usCol <= usTotalCols; usCol++ ) {
if( odbColTruncated( hQry, usCol ) ) {
fprintf( stderr,
"Warning: Col %u was truncated. Actual size is %i.\n",
usCol, odbColActualLen( hQry, usCol ) );
}
if( usCol > 1 ) printf( "," );
if( !(pData = odbColData( hQry, usCol )) ) {
printf( "NULL" );
continue;
}
switch( odbColDataType( hQry, usCol ) ) {
case ODB_BIT:
printf( "%u", (odbULONG)*((odbPBYTE)pData) ); break;
case ODB_TINYINT:
printf( "%i", (odbLONG)*((odbPBYTE)pData) ); break;
case ODB_UTINYINT:
printf( "%u", (odbULONG)*((odbPBYTE)pData) ); break;
case ODB_SMALLINT:
printf( "%i", (odbLONG)*((odbPSHORT)pData) ); break;
case ODB_USMALLINT:
printf( "%u", (odbULONG)*((odbPUSHORT)pData) ); break;
case ODB_INT:
printf( "%i", *((odbPLONG)pData) ); break;
case ODB_UINT:
printf( "%u", *((odbPULONG)pData) ); break;
case ODB_BIGINT:
printf( "%s", odbLongLongToStr( *((odbPLONGLONG)pData), &sz[31] ) ); break;
case ODB_UBIGINT:
printf( "%s", odbULongLongToStr( *((odbPULONGLONG)pData), &sz[31] ) ); break;
case ODB_REAL:
printf( "%g", *((odbPFLOAT)pData) ); break;
case ODB_DOUBLE:
printf( "%lg", *((odbPDOUBLE)pData) ); break;
case ODB_DATETIME:
pts = (odbPTIMESTAMP)pData;
printf( "%04i-%02i-%02i %02i:%02i:%02i.%i",
pts->sYear, pts->usMonth, pts->usDay,
pts->usHour, pts->usMinute, pts->usSecond,
pts->ulFraction );
break;
case ODB_CHAR:
case ODB_WCHAR:
PrintTextData( (odbPCSTR)pData,
odbColDataLen( hQry, usCol ) );
break;
default:
PrintBinaryData( (odbPBYTE)pData,
odbColDataLen( hQry, usCol ) );
}
}
printf( "\n" );
}
return( bOK );
}
void RightTrim( odbPSTR pszText )
{
odbPSTR psz = pszText + strlen(pszText) - 1;
for( ; *psz <= ' ' && psz >= pszText; psz-- ) *psz = 0;
}
void PrintTextData( odbPCSTR pszText, odbLONG lLen )
{
if( lLen < 0 ) lLen = strlen(pszText);
putc( '\"', stdout );
for( ; lLen > 0; lLen--, pszText++ ) {
putc( *pszText, stdout );
if( *pszText == '\"' ) putc( '\"', stdout );
}
putc( '\"', stdout );
}
void PrintBinaryData( odbPBYTE pbyData, odbLONG lLen )
{
odbPCSTR pszHex = "0123456789ABCDEF";
if( lLen <= 0 ) return;
putc( '0', stdout );
putc( 'x', stdout );
for( ; lLen > 0; lLen--, pbyData++ ) {
putc( *(pszHex + ((*pbyData >> 4) & 0x0F)), stdout );
putc( *(pszHex + (*pbyData & 0x0F)), stdout );
}
}