Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCI_GetStruct calculates incorrect offset when a properly aligned Double is followed by an Int #12

Closed
JamesL2 opened this issue Sep 2, 2015 · 10 comments
Assignees

Comments

@JamesL2
Copy link

JamesL2 commented Sep 2, 2015

The existing OCI_GetStruct alignment calculation needs to be updated.

Summary:

For the table:
create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30));

Expected C structure:
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8 :: column is natually aligned - no adjustment needed
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // offset 24 :: don't abend on buffer overflow
} prd;

Actual C structure needed for OCI_GetStruct:
struct product2_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
char *bad_align; // offset 8 :: structure alignment calculation is skipping 4 extra bytes
float val_double; // offset 12 :: cheat to get the alignment being calculated
float val_double2; // offset 16
int val_long; // offset 20
char *val_char_3; // offset 24
char *extra; // offset 28 :: don't abend on buffer overflow
} prd2;


Details:

New OCI_GetStruct function:

/* --------------------------------------------------------------------------------------------- *

  • OCI_GetStruct
  • --------------------------------------------------------------------------------------------- */

boolean OCI_API OCI_GetStructNew
(
OCI_Resultset *rs,
void *row_struct,
void *row_struct_ind
)
{
char *ptr = NULL;
boolean *inds = NULL;

size_t alignOffset;

// size_t alignForMax = 0;

OCI_LIB_CALL_ENTER(boolean, FALSE)

OCI_CHECK_PTR(OCI_IPC_RESULTSET, rs)
OCI_CHECK_PTR(OCI_IPC_VOID, row_struct)

call_status = TRUE;

ptr  = (char    *) row_struct;
inds = (boolean *) row_struct_ind;

// ptr should start at a proper double (8 byte) alignment
if (ptr)
{
size_t structSize = 0;
size_t size1 = 0;
size_t align1 = 0;
ub4 i;

    for (i = 1; i <= rs->nb_defs; i++)
    {
        OCI_Column *col1 = &rs->defs[i-1].col;

        boolean is_not_null = OCI_DefineIsDataNotNull(&rs->defs[i-1]);

        OCI_ColumnGetAttrInfo(col1, rs->nb_defs, i-1, &size1, &align1);

    // ensure the pointer is properly aligned for this column
        if (align1) // avoid divide by zero
        {

// if (alignForMax < align1)
// {
// alignForMax = align1; // remember the largest alignment for this structure
// }

            alignOffset = structSize % align1;  // how far off is the alignment?
            if (alignOffset)
            {
            // adjust the pointer for this field
                size_t alignDelta = (align1 - alignOffset);

                ptr        += alignDelta;
                structSize += alignDelta;
            }
        }

        memset(ptr, 0, size1);

        if (is_not_null)
        {
            switch (col1->datatype)
            {
                case OCI_CDT_NUMERIC:
                {
                    OCI_DefineGetNumber(rs, i, ptr, col1->subtype, (uword) size1);

                    break;
                }
                case OCI_CDT_TEXT:
                {
                    *((otext **) ptr) =  (otext * ) OCI_GetString(rs, i);
                    break;
                }
                case OCI_CDT_RAW:
                {
                    *((void **) ptr) = OCI_DefineGetData(&rs->defs[i]);
                    break;
                }
                case OCI_CDT_LONG:
                {
                    *((OCI_Long **) ptr) = OCI_GetLong(rs, i);
                    break;
                }
                case OCI_CDT_DATETIME:
                {
                    *((OCI_Date **) ptr) = OCI_GetDate(rs, i);
                    break;
                }
                case OCI_CDT_CURSOR:
                {
                    *((OCI_Statement **) ptr) = OCI_GetStatement(rs, i);
                    break;
                }
                case OCI_CDT_LOB:
                {
                    *((OCI_Lob **) ptr) = OCI_GetLob(rs, i);
                    break;
                }
                case OCI_CDT_FILE:
                {
                    *((OCI_File **) ptr) = OCI_GetFile(rs, i);
                    break;
                }
                case OCI_CDT_TIMESTAMP:
                {
                    *((OCI_Timestamp **) ptr) = OCI_GetTimestamp(rs, i);

                    break;
                }
                case OCI_CDT_INTERVAL:
                {
                    *((OCI_Interval **) ptr) = OCI_GetInterval(rs, i);
                    break;
                }
                case OCI_CDT_OBJECT:
                {
                    *((OCI_Object **) ptr) = OCI_GetObject(rs, i);
                    break;
                }
                case OCI_CDT_COLLECTION:
                {
                    *((OCI_Coll **) ptr) = OCI_GetColl(rs, i);
                    break;
                }
                case OCI_CDT_REF:
                {
                    *((OCI_Ref **) ptr) = OCI_GetRef(rs, i);
                    break;
                }
            }
        }

        structSize += size1;
        ptr        += size1;

        if (inds)
        {
            *inds = is_not_null;

            inds++;
        }
    }

// ensure the structure is properly aligned for array processing

// if (alignForMax)
// {
// alignOffset = ptr % alignForMax; // how far off is the alignment?
// if (alignOffset)
// {
// ptr += (alignForMax - alignOffset); // adjust the pointer for this field
// }
// }
}

call_retval = call_status = TRUE;

OCI_LIB_CALL_EXIT()

}


Test Code:
/*-----------

  • test_setup
    -----------/
    int test_setup (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
    {
    int retval = 0;
    otext *sqlString;

    prnlog("\n- test setup...\n");

    sqlString = OTEXT("create table test_fetch_struct2")
    OTEXT("(val_char_1 varchar2(30)")
    OTEXT(",val_char_2 varchar2(30)")
    OTEXT(",val_double number")
    OTEXT(",val_long number(10)")
    OTEXT(",val_char_3 varchar2(30)")
    OTEXT(")")
    ;
    prnlog("\nExecute: %s\n", sqlString);
    OCI_ExecuteStmt(ociStmt, sqlString);

    sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
    OTEXT("values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1')")
    ;
    prnlog("\nExecute: %s\n", sqlString);
    OCI_ExecuteStmt(ociStmt, sqlString);

    sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
    OTEXT("values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2')")
    ;
    prnlog("\nExecute: %s\n", sqlString);
    OCI_ExecuteStmt(ociStmt, sqlString);

    sqlString = OTEXT("insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) ")
    OTEXT("values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3')")
    ;
    prnlog("\nExecute: %s\n", sqlString);
    OCI_ExecuteStmt(ociStmt, sqlString);

    OCI_Commit(ociConn);

    OCI_ReleaseResultsets(ociStmt);

    return(retval);
    }

/*-------------

  • test cleanup
    -------------/
    int test_cleanup (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
    {
    int retval = 0;

    prnlog("\n- test cleanup...\n");

    oci_nofail = 1; /* ignore errors */

    OCI_ExecuteStmt(ociStmt, OTEXT("drop table test_fetch_struct2"));

    OCI_ReleaseResultsets(ociStmt);
    oci_nofail = 0;

    return(retval);
    }

/*------------------

  • test OCI_GetStruct :: verify structure alignment calculation error when a properly aligned double is followed by an int
    ------------------/
    int test_fetch_struct_bad (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
    {
    int retval = 0;
    int iCnt;

// define the structure expected for the retrieval
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8 :: column is natually aligned - no adjustment needed
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // offset 24 :: don't abend on buffer overflow
} prd;

// define the structure as mapped by the OCI_GetStruct function
struct product2_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
char *bad_align; // offset 8 :: structure alignment calculation is skipping 4 extra bytes
float val_double; // offset 12 :: cheat to get the alignment being calculated
float val_double2; // offset 16
int val_long; // offset 20
char *val_char_3; // offset 24
char *extra; // offset 28 :: don't abend on buffer overflow
} prd2;

struct prodind_t
    {
    boolean   val_char_1;
    boolean   val_char_2;
    boolean   val_double;
    boolean   val_long;
    boolean   val_char_3;
    } ind;

prnlog("\n- Test fetch struct bad: prd...\n"
         "  This shows the val_long, and val_char_3, values shifted to the next column\n");

OCI_ExecuteStmtFmt(ociStmt, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));

ociRset = OCI_GetResultset(ociStmt);

OCI_SetStructNumericType(ociRset, 3, OCI_NUM_DOUBLE);
OCI_SetStructNumericType(ociRset, 4, OCI_NUM_INT);

iCnt = 0;
while (OCI_FetchNext(ociRset))
{
    prd.extra = 0;

    OCI_GetStruct(ociRset, &prd, &ind);
    iCnt++;

    prnlog("\nrow %d\n", iCnt);
    prnlog("  > val_char_1 : %08X: %s\n", prd.val_char_1, prd.val_char_1);
    prnlog("  > val_char_2 : %08X: %s\n", prd.val_char_2, prd.val_char_2);
    prnlog("  > val_double : %Lf\n",      prd.val_double);
    prnlog("  > val_long : %d\n",         prd.val_long);
    prnlog("  > val_char_3 : %08X\n",     prd.val_char_3);
    prnlog("  > extra      : %08X: %s\n", prd.extra, prd.extra);
    prnlog("\n");
}
prnlog("  + %d row(s) fetched\n", OCI_GetRowCount(ociRset));

OCI_ReleaseResultsets(ociStmt);

// //////////////////////////

prnlog("\n- test fetch struct bad: prd2...\n"
         "  This shows the structure as mapped by the OCI_GetStruct logic\n");

OCI_ExecuteStmtFmt(ociStmt, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));

ociRset = OCI_GetResultset(ociStmt);

OCI_SetStructNumericType(ociRset, 3, OCI_NUM_DOUBLE);
OCI_SetStructNumericType(ociRset, 4, OCI_NUM_INT);

iCnt = 0;
while (OCI_FetchNext(ociRset))
{
    prd2.extra = 0;

    OCI_GetStruct(ociRset, &prd2, &ind);
    iCnt++;

    prnlog("\nrow %d\n", iCnt);
    prnlog("  > val_char_1 : %08X: %s\n", prd2.val_char_1, prd2.val_char_1);
    prnlog("  > val_char_2 : %08X: %s\n", prd2.val_char_2, prd2.val_char_2);
    prnlog("  > val_double : %Lf\n",      *(double *)&(prd2.val_double));
    prnlog("  > val_long : %d\n",         prd2.val_long);
    prnlog("  > val_char_3 : %08X: %s\n", prd2.val_char_3, prd2.val_char_3);
    prnlog("  > extra      : %08X:\n",    prd2.extra);
    prnlog("\n");
}
prnlog("  + %d row(s) fetched\n", OCI_GetRowCount(ociRset));

OCI_ReleaseResultsets(ociStmt);

retval = oci_rc;

return(retval);

}
/*------------------

  • test_fetch_struct
    ------------------/
    int test_fetch_struct_new (OCI_Connection *ociConn, OCI_Statement *ociStmt, OCI_Resultset *ociRset)
    {
    int retval = 0;
    int iCnt;

    struct product_t
    {
    char *val_char_1; // offset 0
    char *val_char_2; // offset 4
    double val_double; // offset 8
    int val_long; // offset 16
    char *val_char_3; // offset 20
    char *extra; // don't abend on overflow
    } prd;

    struct prodind_t
    {
    boolean val_char_1;
    boolean val_char_2;
    boolean val_double;
    boolean val_long;
    boolean val_char_3;
    } ind;

    prnlog("\n- test fetch struct new: prd...\n"
    " This shows the structure properly mapped by the updated logic\n");

    OCI_ExecuteStmtFmt(ociStmt, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));

    ociRset = OCI_GetResultset(ociStmt);

    OCI_SetStructNumericType(ociRset, 3, OCI_NUM_DOUBLE);
    OCI_SetStructNumericType(ociRset, 4, OCI_NUM_INT);

    iCnt = 0;
    while (OCI_FetchNext(ociRset))
    {
    prd.extra = 0;

    OCI_GetStructNew(ociRset, &prd, &ind);
    iCnt++;
    
    prnlog("\nrow %d\n", iCnt);
    prnlog("  > val_char_1 : %08X: %s\n", prd.val_char_1, prd.val_char_1);
    prnlog("  > val_char_2 : %08X: %s\n", prd.val_char_2, prd.val_char_2);
    prnlog("  > val_double : %Lf\n",      prd.val_double);
    prnlog("  > val_long : %d\n",         prd.val_long);
    prnlog("  > val_char_3 : %08X : %s\n",prd.val_char_3, prd.val_char_3);
    prnlog("  > extra      : %08X\n",     prd.extra);
    
    prnlog("\n");
    

    }
    prnlog(" + %d row(s) fetched\n", OCI_GetRowCount(ociRset));

    OCI_ReleaseResultsets(ociStmt);

    retval = oci_rc;

    return(retval);
    }


Test output:

OCI Test

  • Arguments:
    Oracle User : xxxxxxxx
    Oracle DBName : myOraDB
    Connect Role :
  • Verify Settings
  • OCI Initialize
  • Processing OCI request...
  • Begin OCIThread-00B81C78
  • test cleanup...
    INFO-ORA-00942: table or view does not exist
  • test setup...

Execute: create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30))

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1')

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2')

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3')

  • Test fetch struct bad: prd...
    This shows the val_long, and val_char_3, values shifted to the next column

row 1

val_char_1 : 007FB3C0: col1 row1
val_char_2 : 007FCC50: col2 row1
val_double : -92559641157289301000000000000000000000000000000000000000000000.000000
val_long : 1079958732
val_char_3 : 00000001
extra : 00A31FE8: col5 row1

row 2

val_char_1 : 007FB439: col1 row1
val_char_2 : 007FCCC9: col2 row2
val_double : -0.000000
val_long : 1080906219
val_char_3 : 00000002
extra : 00A32061: col5 row2

row 3

val_char_1 : 007FB4B2: col1 row1
val_char_2 : 007FCD42: col2 row3
val_double : 427698049712232160000000000000000000000000000000000000000000000000000000000000000000000.000000
val_long : 1081449144
val_char_3 : 00000003
extra : 00A320DA: col5 row3

  • 3 row(s) fetched
  • test fetch struct bad: prd2...
    This shows the structure as mapped by the OCI_GetStruct logic

row 1

val_char_1 : 00A32348: col1 row1
val_char_2 : 007FB088: col2 row1
val_double : 123.450000
val_long : 1
val_char_3 : 007FD0E8: col5 row1
extra : 00000000:

row 2

val_char_1 : 00A323C1: col1 row1
val_char_2 : 007FB101: col2 row2
val_double : 234.560000
val_long : 2
val_char_3 : 007FD161: col5 row2
extra : 00000000:

row 3

val_char_1 : 00A3243A: col1 row1
val_char_2 : 007FB17A: col2 row3
val_double : 345.670000
val_long : 3
val_char_3 : 007FD1DA: col5 row3
extra : 00000000:

  • 3 row(s) fetched
  • test fetch struct new: prd...
    This shows the structure properly mapped by the updated logic

row 1

val_char_1 : 00A32348: col1 row1
val_char_2 : 007FB088: col2 row1
val_double : 123.450000
val_long : 1
val_char_3 : 007FD0E8 : col5 row1
extra : 00000000

row 2

val_char_1 : 00A323C1: col1 row1
val_char_2 : 007FB101: col2 row2
val_double : 234.560000
val_long : 2
val_char_3 : 007FD161 : col5 row2
extra : 00000000

row 3

val_char_1 : 00A3243A: col1 row1
val_char_2 : 007FB17A: col2 row3
val_double : 345.670000
val_long : 3
val_char_3 : 007FD1DA : col5 row3
extra : 00000000

  • 3 row(s) fetched
  • test cleanup...
  • OCI Disconnect: xxxxxxxx/***@myOraDB
  • End OCIThread-00B81C78
  • OCI Cleanup

OCILib Errors = 0
Oracle Errors = 0
Oracle Warnings= 0

@vrogier
Copy link
Owner

vrogier commented Sep 2, 2015

Hi,

Can you indicate the ocilib version , the oracle version and the platform (32/64bits) ?

The following code (taken from you) give the expected results on Win32/Oracle 12c:

int main()
{
    OCI_Connection* cn;
    OCI_Statement* st;
    OCI_Resultset* rs;

    int i;

    OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT);

    cn = OCI_ConnectionCreate("db12c", "usr", "pwd", OCI_SESSION_DEFAULT);
    st = OCI_StatementCreate(cn);

    OCI_ExecuteStmtFmt(st, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));

    rs = OCI_GetResultset(st);

    OCI_SetStructNumericType(rs, 3, OCI_NUM_DOUBLE);
    OCI_SetStructNumericType(rs, 4, OCI_NUM_INT);

    i = 0;
    while (OCI_FetchNext(rs))
    {
        prd.val_char_1 = 0;
        prd.val_char_2 = 0;
        prd.val_double = 0.0;
        prd.val_long = 0;
        prd.val_char_3 = 0;
        prd.extra = 0;

        OCI_GetStruct(rs, &prd, &ind);
        i++;

        printf("\nrow %d\n", i);
        printf("  > val_char_1 : %08X: %s\n", prd.val_char_1, prd.val_char_1);
        printf("  > val_char_2 : %08X: %s\n", prd.val_char_2, prd.val_char_2);
        printf("  > val_double : %Lf\n", prd.val_double);
        printf("  > val_long : %d\n", prd.val_long);
        printf("  > val_char_3 : %08X %s\n", prd.val_char_3, prd.val_char_3);
        printf("  > extra      : %08X: %s\n", prd.extra, prd.extra);
        printf("\n");
    }

    OCI_Cleanup();

    return EXIT_SUCCESS;
}

the output is :

row 1

val_char_1 : 00203670: col1 row1
val_char_2 : 00203A60: col2 row1
val_double : 123.450000
val_long : 1
val_char_3 : 002044D0 col5 row1
extra : 00000000: (null)

row 2

val_char_1 : 0020368F: col1 row2
val_char_2 : 00203A7F: col2 row2
val_double : 234.560000
val_long : 2
val_char_3 : 002044EF col5 row2
extra : 00000000: (null)

row 3

val_char_1 : 002036AE: col1 row3
val_char_2 : 00203A9E: col2 row3
val_double : 345.670000
val_long : 3
val_char_3 : 0020450E col5 row3
extra : 00000000: (null)

Vincent

@JamesL2
Copy link
Author

JamesL2 commented Sep 2, 2015

Changelog.txt: 2015-05-05 Version 4.1.0 Vincent Rogier vince.rogier@ocilib.net

Using Windows, lib32, ociliba.dll, Oracle 11.2g

#define OCI_CHARSET_ANSI
#define OCI_IMPORT_RUNTIME

@vrogier
Copy link
Owner

vrogier commented Sep 3, 2015

Hi,

Can you try the code I've posted and tell me what results you got ?

Thanks

@JamesL2
Copy link
Author

JamesL2 commented Sep 3, 2015

Posted code modified to:
include structure definitions;
create, populate, and delete the oracle table using functions previously posted;
accept connection parameters;
split printing prd.val_char_3 into two statements in order to see the pointer value before attempting to use it.


output results:

  • test cleanup...
  • test setup...

Execute: create table test_fetch_struct2(val_char_1 varchar2(30),val_char_2 varchar2(30),val_double number,val_long number(10),val_char_3 varchar2(30))

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row1', 123.45, 1, 'col5 row1')

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row2', 234.56, 2, 'col5 row2')

Execute: insert into test_fetch_struct2 (val_char_1, val_char_2, val_double, val_long, val_char_3) values ('col1 row1', 'col2 row3', 345.67, 3, 'col5 row3')

row 1

val_char_1 : 009C7FE8: col1 row1
val_char_2 : 009C89C8: col2 row1
val_double : -92559641157289301000000000000000000000000000000000000000000000.000000
val_long : 1079958732
val_char_3 : 00000001

A segment fault (signal 11) occurs attempting to print the string referenced by prd.val_char_3.


int main(int argc, oarg* argv[])
{
OCI_Connection* cn = 0;
OCI_Statement* st = 0;
OCI_Resultset* rs = 0;

int i;

// define the structure expected for the retrieval
struct product_t
{
char *val_char_1; // offset 0
char *val_char_2; // offset 4
double val_double; // offset 8 :: column is natually aligned - no adjustment needed
int val_long; // offset 16
char *val_char_3; // offset 20
char *extra; // offset 24 :: don't abend on buffer overflow
} prd;

struct prodind_t
{
    boolean   val_char_1;
    boolean   val_char_2;
    boolean   val_double;
    boolean   val_long;
    boolean   val_char_3;
} ind;

orauser[0] = '\0';
orapswd[0] = '\0';
dbalias[0] = '\0';
orarole[0] = '\0';

GET_ARG(orauser, ARG_USER);
GET_ARG(orapswd, ARG_PWD);
GET_ARG(dbalias, ARG_ALIAS);

OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT);

// cn = OCI_ConnectionCreate("db12c", "usr", "pwd", OCI_SESSION_DEFAULT);
if ((cn = OCI_ConnectionCreate(dbalias, orauser, orapswd, OCI_SESSION_DEFAULT)) == NULL)
{
return(1);
}
if ((st = OCI_StatementCreate(cn)) == NULL)
{
return(1);
}

test_cleanup(cn, st, rs);
test_setup(cn, st, rs);

OCI_ExecuteStmtFmt(st, OTEXT("select val_char_1, val_char_2, val_double, val_long, val_char_3 from test_fetch_struct2"));

rs = OCI_GetResultset(st);

OCI_SetStructNumericType(rs, 3, OCI_NUM_DOUBLE);
OCI_SetStructNumericType(rs, 4, OCI_NUM_INT);

i = 0;
while (OCI_FetchNext(rs))
{
    prd.val_char_1 = 0;
    prd.val_char_2 = 0;
    prd.val_double = 0.0;
    prd.val_long = 0;
    prd.val_char_3 = 0;
    prd.extra = 0;

    OCI_GetStruct(rs, &prd, &ind);
    i++;

    printf("\nrow %d\n", i);
    printf("  > val_char_1 : %08X: %s\n", prd.val_char_1, prd.val_char_1);
    printf("  > val_char_2 : %08X: %s\n", prd.val_char_2, prd.val_char_2);
    printf("  > val_double : %Lf\n", prd.val_double);
    printf("  > val_long : %d\n", prd.val_long);
    printf("  > val_char_3 : %08X", prd.val_char_3);
    printf("%s\n", prd.val_char_3);
    printf("  > extra      : %08X: %s\n", prd.extra, prd.extra);
    printf("\n");
}

test_cleanup(cn, st, rs);

OCI_Cleanup();

return EXIT_SUCCESS;

}

@vrogier
Copy link
Owner

vrogier commented Sep 3, 2015

What compiler are you using ?

@JamesL2
Copy link
Author

JamesL2 commented Sep 3, 2015

MSVC 2010 generating 32bit executable.
Compiling & executing computer is Windows 7x64 professional & enterprise edition.

@JamesL2
Copy link
Author

JamesL2 commented Sep 3, 2015

Print statements added before the fetch loop:

#define PTR_DIFF(ptr1,ptr2) ((long)ptr1 - (long)ptr2)
printf("\nprd column offsets\n");
printf("  > val_char_1 : %08X, %2d\n", &prd.val_char_1, PTR_DIFF(&prd.val_char_1, &prd));
printf("  > val_char_2 : %08X, %2d\n", &prd.val_char_2, PTR_DIFF(&prd.val_char_2, &prd));
printf("  > val_double : %08X, %2d\n", &prd.val_double, PTR_DIFF(&prd.val_double, &prd));
printf("  > val_long   : %08X, %2d\n", &prd.val_long,   PTR_DIFF(&prd.val_long,   &prd));
printf("  > val_char_3 : %08X, %2d\n", &prd.val_char_3, PTR_DIFF(&prd.val_char_3, &prd));
printf("  > extra      : %08X, %2d\n", &prd.extra,      PTR_DIFF(&prd.extra,      &prd));

produces:

prd column offsets
  > val_char_1 : 002EF898,  0
  > val_char_2 : 002EF89C,  4
  > val_double : 002EF8A0,  8
  > val_long   : 002EF8A8, 16
  > val_char_3 : 002EF8AC, 20
  > extra      : 002EF8B0, 24

Print statements added to the OCI_GetStruct function (around the existing ROUNDUP logic):

printf("\nOCI_GetStruct: \n");
:
:
printf("\ti=%3d ptr=%08X size1=%3d align1=%2d size2=%3d align2=%2d", (int)i, ptr, (int)size1, (int)align1, (int)size2, (int)align2);
if (size2 > 0)
{
    size1 = ROUNDUP(size1, align2);
    printf(" size1 roundup: %d", (int)size1);
}
printf("\n");

produces the following, where the 2nd roundup should be 4 instead of 8:

OCI_GetStruct:
    i=  1 ptr=002EF898 size1=  4 align1= 4 size2=  4 align2= 4 size1 roundup: 4
    i=  2 ptr=002EF89C size1=  4 align1= 4 size2=  8 align2= 8 size1 roundup: 8
    i=  3 ptr=002EF8A4 size1=  8 align1= 8 size2=  4 align2= 4 size1 roundup: 8
    i=  4 ptr=002EF8AC size1=  4 align1= 4 size2=  4 align2= 4 size1 roundup: 4
    i=  5 ptr=002EF8B0 size1=  4 align1= 4 size2=  0 align2= 4

@vrogier
Copy link
Owner

vrogier commented Sep 3, 2015

Hi,

You were right indeed. My test and posted code were done using an 64bits build of OCILIB by mistake.
Using a 32bits build, i got the same issues than you.
I've committed a fix for it.
Now on both 32bits and 64bits platforms, results are correct !

Thanks :)

Regards,

Vincent

@vrogier
Copy link
Owner

vrogier commented Sep 4, 2015

Hi,

Is that alright fro you ?

Thanks

Vincent

@JamesL2
Copy link
Author

JamesL2 commented Sep 4, 2015

A fix to the issue is good.
Thank you.

While I am not using these functions, I did notice the same logic is used in the OCI_ObjectGetStructSize and OCI_ObjectGetUserStructSize functions, in case they also need an update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants