ODBC/inline driver ignores transactions.

Daniel Bruce Lynes dlynes1 at home.com
Tue Jul 4 05:46:07 EDT 2000


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




More information about the FreeTDS mailing list