Topic
  • 1 reply
  • Latest Post - ‏2009-02-17T09:35:36Z by SystemAdmin
SystemAdmin
SystemAdmin
262 Posts

Pinned topic Segmentation fault in SQLExecute

‏2009-02-16T16:55:49Z |
I've installed UnixODBC and iseriesAccess for linux (5.4) to connect to our iseries.

I've compiled a c program, helloODBC.c and it works.

When I modify it to use prepared statement, as follows, I get a segmentation fault.

bart@LxPC37:~/download/software/mono/src/test$ ./helloODBCPrep Dunkel siapbn siapbn75
Here1!!
Here2!!
Segmentation fault

I've switched on unixodbc log and I got:


ODBC 14289 http://SQLPrepare.c 189
Entry:
Statement = 0x80690e0
SQL = http://SELECT * FROM VIAGGIFAM.PWKCXM WHERE WKXSCX=? length = 45 (SQL_NTS)
ODBC 14289 http://SQLPrepare.c 364
Exit: SQL_SUCCESS
ODBC 14289 http://SQLBindParameter.c 193
Entry:
Statement = 0x80690e0
Param Number = 1
Param Type = 1
C Type = 1 SQL_C_CHAR
SQL Type = 1 SQL_CHAR
Col Def = 2
Scale = 0
Rgb Value = 0x80491ae
Value Max = 2
StrLen Or Ind = 0xfffffffd
ODBC 14289 http://SQLBindParameter.c 339
Exit: SQL_SUCCESS
ODBC 14289 http://SQLExecute.c 183
Entry:
Statement = 0x80690e0



/* helloODBCPrep
Simple ODBC example for Linux
Arguments: datasource (name of your System or User DSN)
UserID
password
Example: ODBCexample datasource UserID password
Rochester, MN, July 2005 */
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Simple query to DB table very likely to exist. Takes first i5/OS "member" */
char querystring[] = "SELECT * FROM VIAGGIFAM.PWKCXM WHERE WKXSCX=?";
char param1[]= "KU";

void
die (char *reason, SQLRETURN code)
{
if (code != 0)
{
printf ("Error code: %d\n", code);
}
printf ("Failure because: %s\n", reason);
exit (1);
}
int
main (int argc, char *argv[])
{
#define MAX_CONNECTIONS 5
char field1 255; /*receives values from table row fetch */
char field2 255;
char field3 255;
SQLINTEGER retfld1;
/* For completelness. */
SQLINTEGER retfld2; /* For this example, NULL for SQLBindCol */
SQLINTEGER retfld3; /* would be enough */
SQLHENV henv;
SQLHDBC hdbc MAX_CONNECTIONS; /* For multiple connections */
SQLHSTMT statement;
SQLRETURN sqe = 0;
SQLRETURN res = 0;
/* allocate environment */
if (SQLAllocEnv (&henv))
die ("Alloc Environment", 0);
/* allocate connection */
if ((sqe = SQLAllocConnect (henv, &hdbc[0])))
die ("Allocate Connect", sqe);
/* connect to data base */
if ((sqe = SQLConnect (hdbc[0], argv[1], SQL_NTS,
argv[2], SQL_NTS, argv[3], SQL_NTS)))
die ("Connect", sqe);
/* allocate statement(s) */
if (SQLAllocStmt (hdbc[0], &statement))
die ("Alloc stmt", 0);
/*
SQLRETURN SQLPrepare(
SQLHSTMT StatementHandle,
SQLCHAR * StatementText,
SQLINTEGER TextLength

*/
if( sqe= SQLPrepare( /* SQLHSTMT StatementHandle*/ statement,
/*SQLCHAR * StatementText*/ (SQLCHAR *) querystring,
/*strlen( querystring )*/ SQL_NTS)){
die ("prepare:", sqe);
}

/*
SQLRETURN SQLBindParameter(
SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber,
SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType,
SQLSMALLINT ParameterType,
SQLULEN ColumnSize,
SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr,
SQLINTEGER BufferLength,
SQLLEN * StrLen_or_IndPtr);
*/

printf("Here1!!\n");

if( sqe= SQLBindParameter(
/*SQLHSTMT StatementHandle*/ statement,
/*SQLUSMALLINT ParameterNumber*/ 1,
/*SQLSMALLINT InputOutputType*/ SQL_PARAM_INPUT,
/*SQLSMALLINT ValueType*/ SQL_C_CHAR,
/*SQLSMALLINT ParameterType*/ SQL_CHAR,
/*SQLULEN ColumnSize*/ 2,
/*SQLSMALLINT DecimalDigits*/ 0,
/*SQLPOINTER ParameterValuePtr*/ param1,
/*SQLINTEGER BufferLength*/ 2,
/*SQLLEN * StrLen_or_IndPtr*/ SQL_NTS)){
die ("bind:", sqe);
}

printf("Here2!!\n");

/* Do query */
/*
SQLRETURN SQLExecute(
SQLHSTMT StatementHandle);
*/
if ((sqe = SQLExecute (statement)))
die ("exec direct", sqe);

printf("Here2!!\n");

/* Bind coming SQLFetch operations to fields */
if ((sqe = SQLBindCol (statement, 1, SQL_CHAR, field1, 255, &retfld1)))
die ("Bind field 1", sqe);
if ((sqe = SQLBindCol (statement, 2, SQL_CHAR, field2, 255, &retfld2)))
die ("Bind field 2", sqe);
if ((sqe = SQLBindCol (statement, 3, SQL_CHAR, field3, 255, &retfld3)))
die ("Bind field 3", sqe);
/* While loop to fetch all records */
res = SQLFetch (statement);
/* field1,2,3 take new values each time */
while (SQL_SUCCEEDED (res))
{ /* Create tab separated values */
printf ("%s\t%s\t%s\n", field1, field2, field3);
res = SQLFetch (statement); /* next record */
}
/* end actual processing */
/* free statement(s) pretty completely */
if (SQLFreeStmt (statement, SQL_DROP))
die ("Free Statement with Drop", 0);
/* close connection */
if ((sqe = SQLDisconnect (hdbc[0])))
die ("Disconnect ", sqe);
if ((sqe = SQLFreeConnect (hdbc[0])))
die ("Connection closed", sqe);
/* free environment */
if (SQLFreeEnv (henv))
die ("Free Environment", 0);
printf ("Success!\n");
return 0;
}

Updated on 2009-02-17T09:35:36Z at 2009-02-17T09:35:36Z by SystemAdmin
  • SystemAdmin
    SystemAdmin
    262 Posts

    Re: Segmentation fault in SQLExecute

    ‏2009-02-17T09:35:36Z  
    The problem iss the call to SQLBindParameter
    where passing SQL_NTS as the length but SQL_NTS is not a
    SQLLEN*. I think that should be:

    SQLLEN param_length;
    param_length = SQL_NTS;

    if( sqe= SQLBindParameter(
    /*SQLHSTMT StatementHandle*/ statement,
    /*SQLUSMALLINT ParameterNumber*/ 1,
    /*SQLSMALLINT InputOutputType*/ SQL_PARAM_INPUT,
    /*SQLSMALLINT ValueType*/ SQL_C_CHAR,
    /*SQLSMALLINT ParameterType*/ SQL_CHAR,
    /*SQLULEN ColumnSize*/ 50,
    /*SQLSMALLINT DecimalDigits*/ 0,
    /*SQLPOINTER ParameterValuePtr*/ param1,
    /*SQLINTEGER BufferLength*/ 0,
    /*SQLLEN * StrLen_or_IndPtr*/ &param_length)){
    die ("bind:", sqe);
    }

    IIRC, SQL_NTS is -3 so passing SQL_NTS as the last argument to
    SQLBindParameter would cause the driver to read address -3 which could
    cause a problem.