Skip to Content.
Sympa Menu

freetds - Re: ODBC/inline driver ignores transactions.

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Daniel Bruce Lynes <dlynes1 AT home.com>
  • To: TDS Development Group <freetds AT franklin.oit.unc.edu>
  • Subject: Re: ODBC/inline driver ignores transactions.
  • Date: Tue, 4 Jul 2000 02:46:07 -0700 (PDT)


Here are my updates to the odbc driver sources, I was referring to, Brian.

Some explanation of the changes is in order:

connectparams.c:

- added code to strip leading and trailing space from strings
- updated hash function to call string space killer before a compare and a
hash
calculation
- replaced glib strcmp function with a new function that calls the space
remover
function, and later calls strcmp()
- modified the NewConnectParams() function to account for the new strcmp()
function

odbc.c:

- wrote the body for the SQLGetFunctions() function
- added getStmtType() function, to determine the statement type; this was
needed
so that SQLExecute() didn't errantly return an error if it was called for a
SQL command that doesn't generate a data packet, such as insert, update and
delete SQL functions
- updated SQLDriverConnect() and SQLConnect() to account for a port number
- updated _odbc_get_server_type() and _odbc_get_client_type() to handle some
data types that they weren't handling
- removed extraneous breaks from switch cases in _odbc_get_client_type()

Makefile:

- modified one line so that it's linking in the static library for tdslib now,
instead of doing whatever it was doing with the shared libraries

Where appropriate I have also put in conditional preprocessing to allow
compilation under Win32 and OS/2, also.

Sorry about the lengthy post, but I've made a lot of changes to the driver.

ttfn.

Best wishes

Daniel

Below are the changes:
----------------------

connectparams.c:

/*
* Private prototypes added
*/
void lTrimString( char * str ) ;
void rTrimString(char *str) ;
void trimString(char *str) ;
gint str_equal( gconstpointer v, gconstpointer v2 ) ;

/*********************************************************
* Function: void ITrimString( char * str ) ;
*
* Purpose: Erase all the space at the beginning of the
* string.
*
* Notes:
*
* Date written: Thursday, June 08, 2000
* Last update: Thursday, June 08, 2000
*
* Input: str - string to work on
*
* Output: NONE
********************************************************/
void lTrimString( char * str )
{
char * p ;
char * d ;
if (!str)
return;

// skip the the first char in the string that is space
p = str;
while (isspace(*p) )
p++;

// copy the none-space part to the
d = str;
while (*p)
*d++ = *p++;
*d = '\0';
}

void rTrimString(char *str)
{
int len ;
char * p ;
if (!str)
return;
len = strlen(str);
p = &str[len-1];
while (p>=str){
if (isspace(*p))
p--;
//***BWU
else
break ;
//***
}
*++p = '\0';
}

void trimString(char *str)
{
if (!str)
return;

lTrimString(str);
rTrimString(str);
}

/*
* Allocate create a ConnectParams object
*/

ConnectParams* NewConnectParams ()
{
ConnectParams* params = malloc (sizeof (ConnectParams));
if (!params)
return params;

params->dsnName = g_string_new ("");
params->iniFileName = NULL;
params->table = g_hash_table_new (HashFunction, str_equal);

return params;
}

/*
* Make a hash from all the characters
*/
static guint HashFunction (gconstpointer key)
{
guint value = 0;
char buffer[256] ;
const char* s = buffer;

strcpy( buffer, ( char * )key ) ;
trimString( buffer ) ;

while (*s) value += *s++;

return value;
}

odbc.c:

SQLRETURN SQL_API SQLDriverConnect(
SQLHDBC hdbc,
SQLHWND hwnd,
SQLCHAR FAR *szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR FAR *szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT FAR *pcbConnStrOut,
SQLUSMALLINT fDriverCompletion)
{
SQLCHAR FAR* server = NULL;
SQLCHAR FAR* dsn = NULL;
SQLCHAR FAR* uid = NULL;
SQLCHAR FAR* pwd = NULL;
int port = 0 ;
ConnectParams* params;

strcpy (lastError, "");

params = ((ODBCConnection*) hdbc)->params;

if (!(dsn = ExtractDSN (params, szConnStrIn)))
{
LogError ("Could not find DSN in connect string");
return SQL_ERROR;
}
else if (!LookupDSN (params, dsn))
{
LogError ("Could not find DSN in odbc.ini");
return SQL_ERROR;
}
else
{
SetConnectString (params, szConnStrIn);

if (!(server = GetConnectParam (params, "Servername")))
{
char buffer[200] ;
sprintf( buffer, "Could not find Database parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
}
else if (!(uid = GetConnectParam (params, "UID")))
{
char buffer[200] ;
sprintf( buffer, "Could not find UID parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
}
else if (!(pwd = GetConnectParam (params, "PWD")))
{
char buffer[200] ;
sprintf( buffer, "Could not find PWD parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
}
else if( !GetConnectParam( params, "port" ) )
{
char buffer[200] ;
sprintf( buffer, "Could not find port parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
} else
port=atoi( GetConnectParam( params, "port" ) ) ;
}
if( !port )
port=4100 ;

return do_connect (hdbc, server, uid, pwd, port);
}

SQLRETURN SQL_API SQLBindCol(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLSMALLINT fCType,
SQLPOINTER rgbValue,
SQLINTEGER cbValueMax,
SQLINTEGER FAR *pcbValue)
{
/*
* Copied this code from SQLBindParameter because it looks like it
* belongs here. - Ken
*/
TDSCOLINFO * colinfo;
TDSRESULTINFO * resinfo;
TDSSOCKET * tds;
struct _hstmt *stmt;

stmt = (struct _hstmt *) hstmt;
tds = (TDSSOCKET *) stmt->hdbc->tds_socket;
colinfo = tds->res_info->columns[icol-1];
colinfo->varaddr = (char *)rgbValue;
/*
* Added call to _odbc_get_server_type() here - Daniel
*/
colinfo->column_bindtype = _odbc_get_server_type( fCType ) ;
colinfo->column_bindlen = cbValueMax;

return SQL_SUCCESS;
}

SQLRETURN SQL_API SQLConnect(
SQLHDBC hdbc,
SQLCHAR FAR *szDSN,
SQLSMALLINT cbDSN,
SQLCHAR FAR *szUID,
SQLSMALLINT cbUID,
SQLCHAR FAR *szAuthStr,
SQLSMALLINT cbAuthStr)
{
SQLCHAR FAR* server = NULL;
ConnectParams* params;
int port=0 ;

strcpy (lastError, "");

params = ((ODBCConnection*) hdbc)->params;

if (!LookupDSN (params, szDSN))
{
LogError ("Could not find DSN in odbc.ini");
return SQL_ERROR;
}
else if (!(server = GetConnectParam (params, "Servername")))
{
char buffer[200] ;
sprintf( buffer, "Could not find Database parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
} else if( !GetConnectParam( params, "port" ) )
{
char buffer[200] ;
sprintf( buffer, "Could not find port parameter: [%d]:%s\n",
__LINE__, __FILE__ ) ;
LogError (buffer);
return SQL_ERROR;
} else
port=atoi( GetConnectParam( params, "port" ) ) ;

if( !port )
port=4100 ;

return do_connect (hdbc, server, szUID, szAuthStr, port);
}

/*********************************************************
* Function: int getStmtType( char * queryString ) ;
*
* Purpose: Determine the statement type.
*
* Notes:
*
* Date written: Friday, June 30, 2000
* Last update: Friday, June 30, 2000
*
* Input: queryString - query string passed to the ODBC
* driver
*
* Output: 0 - INSERT
* 1 - UPDATE
* 2 - DELETE
* 3 - SELECT
* >3 - Unknown
********************************************************/
int getStmtType( char * queryString )
{
#if defined( WIN32 ) || defined( __OS2__ )
if( memicmp( queryString, "insert", 6 )==0 )
#else
if( strncasecmp( queryString, "insert", 6 )==0 )
#endif
return 0 ;
#if defined( WIN32 ) || defined( __OS2__ )
if( memicmp( queryString, "update", 6 )==0 )
#else
if( strncasecmp( queryString, "update", 6 )==0 )
#endif
return 1 ;
#if defined( WIN32 ) || defined( __OS2__ )
if( memicmp( queryString, "delete", 6 )==0 )
#else
if( strncasecmp( queryString, "delete", 6 )==0 )
#endif
return 2 ;
#if defined( WIN32 ) || defined( __OS2__ )
if( memicmp( queryString, "select", 6 )==0 )
#else
if( strncasecmp( queryString, "select", 6 )==0 )
#endif
return 3 ;

return 4 ;
}

SQLRETURN SQL_API SQLExecute(
SQLHSTMT hstmt)
{
struct _hstmt *stmt = (struct _hstmt *) hstmt;
int ret;

if (!(tds_submit_query(stmt->hdbc->tds_socket, stmt->query)==TDS_SUCCEED))
{
return SQL_ERROR;
}
/* does anyone know how ODBC deals with multiple result sets? */
ret = tds_process_result_tokens(stmt->hdbc->tds_socket);
if (ret==TDS_NO_MORE_RESULTS) {
// If it's an insert, update, or delete, there won't be any data
switch( getStmtType( stmt->query ) ) {
case 0:
case 1:
case 2:
return SQL_SUCCESS ;
}
fprintf( stderr, "SQL_NO_DATA_FOUND with: %s\n", stmt->query ) ;
return SQL_NO_DATA_FOUND;
} else if (ret==TDS_SUCCEED) {
return SQL_SUCCESS;
}
}

SQLRETURN SQL_API SQLGetFunctions(
SQLHDBC hdbc,
SQLUSMALLINT fFunction,
SQLUSMALLINT FAR *pfExists)
{
switch( fFunction ) {
case SQL_API_SQLALLOCCONNECT:
*pfExists=1 ;
break ;

case SQL_API_SQLALLOCENV:
*pfExists=1 ;
break ;

case SQL_API_SQLALLOCSTMT:
*pfExists=1 ;
break ;

case SQL_API_SQLBINDCOL:
*pfExists=1 ;
break ;

case SQL_API_SQLCANCEL:
*pfExists=0 ;
break ;

case SQL_API_SQLCOLATTRIBUTES:
*pfExists=0 ;
break ;

case SQL_API_SQLCONNECT:
*pfExists=1 ;
break ;

case SQL_API_SQLDESCRIBECOL:
*pfExists=1 ;
break ;

case SQL_API_SQLDISCONNECT:
*pfExists=0 ;
break ;

case SQL_API_SQLERROR:
*pfExists=1 ;
break ;

case SQL_API_SQLEXECDIRECT:
*pfExists=1 ;
break ;

case SQL_API_SQLEXECUTE:
*pfExists=1 ;
break ;

case SQL_API_SQLFETCH:
*pfExists=1 ;
break ;

case SQL_API_SQLFREECONNECT:
*pfExists=1 ;
break ;

case SQL_API_SQLFREEENV:
*pfExists=0 ;
break ;

case SQL_API_SQLFREESTMT:
*pfExists=1 ;
break ;

case SQL_API_SQLGETCURSORNAME:
*pfExists=0 ;
break ;

case SQL_API_SQLNUMRESULTCOLS:
*pfExists=1 ;
break ;

case SQL_API_SQLPREPARE:
*pfExists=1 ;
break ;

case SQL_API_SQLROWCOUNT:
*pfExists=0 ;
break ;

case SQL_API_SQLSETCURSORNAME:
*pfExists=0 ;
break ;

case SQL_API_SQLSETPARAM:
*pfExists=0 ;
break ;

case SQL_API_SQLTRANSACT:
*pfExists=0 ;
break ;

case SQL_API_SQLCOLUMNS:
*pfExists=0 ;
break ;

case SQL_API_SQLDRIVERCONNECT:
*pfExists=1 ;
break ;

case SQL_API_SQLGETCONNECTOPTION:
*pfExists=0 ;
break ;

case SQL_API_SQLGETDATA:
*pfExists=1 ;
break ;

case SQL_API_SQLGETFUNCTIONS:
*pfExists=1 ;
break ;

case SQL_API_SQLGETINFO:
*pfExists=0 ;
break ;

case SQL_API_SQLGETSTMTOPTION:
*pfExists=0 ;
break ;

case SQL_API_SQLGETTYPEINFO:
*pfExists=0 ;
break ;

case SQL_API_SQLPARAMDATA:
*pfExists=0 ;
break ;

case SQL_API_SQLPUTDATA:
*pfExists=0 ;
break ;

case SQL_API_SQLSETCONNECTOPTION:
*pfExists=0 ;
break ;

case SQL_API_SQLSETSTMTOPTION:
*pfExists=0 ;
break ;

case SQL_API_SQLSPECIALCOLUMNS:
*pfExists=0 ;
break ;

case SQL_API_SQLSTATISTICS:
*pfExists=0 ;
break ;

case SQL_API_SQLTABLES:
*pfExists=0 ;
break ;

case SQL_API_SQLBROWSECONNECT:
*pfExists=0 ;
break ;

case SQL_API_SQLCOLUMNPRIVILEGES:
*pfExists=0 ;
break ;

case SQL_API_SQLDATASOURCES:
*pfExists=0 ;
break ;

case SQL_API_SQLDESCRIBEPARAM:
*pfExists=0 ;
break ;

case SQL_API_SQLEXTENDEDFETCH:
*pfExists=0 ;
break ;

case SQL_API_SQLFOREIGNKEYS:
*pfExists=0 ;
break ;

case SQL_API_SQLMORERESULTS:
*pfExists=0 ;
break ;

case SQL_API_SQLNATIVESQL:
*pfExists=0 ;
break ;

case SQL_API_SQLNUMPARAMS:
*pfExists=0 ;
break ;

case SQL_API_SQLPARAMOPTIONS:
*pfExists=0 ;
break ;

case SQL_API_SQLPRIMARYKEYS:
*pfExists=0 ;
break ;

case SQL_API_SQLPROCEDURECOLUMNS:
*pfExists=0 ;
break ;

case SQL_API_SQLPROCEDURES:
*pfExists=0 ;
break ;

case SQL_API_SQLSETPOS:
*pfExists=0 ;
break ;

case SQL_API_SQLSETSCROLLOPTIONS:
*pfExists=0 ;
break ;

case SQL_API_SQLTABLEPRIVILEGES:
*pfExists=0 ;
break ;

case SQL_API_SQLDRIVERS:
*pfExists=0 ;
break ;

case SQL_API_SQLBINDPARAMETER:
*pfExists=1 ;
break ;

default:
return SQL_ERROR ;
}

return SQL_SUCCESS;
}

static int _odbc_get_server_type(int clt_type)
{
switch (clt_type) {
case SQL_CHAR:
return SYBCHAR;
case SQL_VARCHAR:
return SYBVARCHAR;
case SQL_BINARY:
return SYBBINARY ;
case SQL_VARBINARY:
return SYBVARBINARY ;
case SQL_BIT:
return SYBBIT;
case SQL_TINYINT:
return SYBINT1;
case SQL_SMALLINT:
return SYBINT2;
case SQL_INTEGER:
return SYBINT4;
case SQL_DOUBLE:
return SYBFLT8;
case SQL_DECIMAL:
return SYBDECIMAL;
case SQL_NUMERIC:
return SYBNUMERIC;
case SQL_FLOAT:
return SYBREAL;
case SQL_DATE:
return SYBDATETIME ;
}
}
static int _odbc_get_client_type(int srv_type)
{
switch (srv_type) {
case SYBCHAR:
return SQL_CHAR;
case SYBVARCHAR:
return SQL_VARCHAR;
case SYBBINARY:
return SQL_BINARY ;
case SYBVARBINARY:
return SQL_VARBINARY ;
case SYBBIT:
return SQL_BIT;
case SYBINT4:
return SQL_INTEGER;
case SYBINT2:
return SQL_SMALLINT;
case SYBINT1:
return SQL_TINYINT;
case SYBREAL:
return SQL_FLOAT;
case SYBFLT8:
return SQL_DOUBLE;
case SYBMONEY:
return SQL_NUMERIC ;
case SYBMONEY4:
return SQL_NUMERIC ;
case SYBDATETIME:
return SQL_DATE;
case SYBNUMERIC:
return SQL_NUMERIC ;
}
}

Makefile:

libtdsodbc_la_LIBADD = -lglib -ltds





Archive powered by MHonArc 2.6.24.

Top of Page