Hello

I'm porting my connection library to Firebird database for the D language, and I'm having problems with "Access Violation" using DMD (did some testing and this problem does not occur with GDC). This code is based on a simple C implementation, and it works ok in VC++ and GCC):

[code]
import std.stdio;
import core.memory;
import std.conv;

alias uint ISC_STATUS;

const ISC_STATUS_LENGTH = 20;
alias ISC_STATUS ISC_STATUS_ARRAY[ISC_STATUS_LENGTH];

alias char ISC_SCHAR;
alias ubyte ISC_UCHAR;

alias int ISC_LONG;
alias uint ISC_ULONG;

alias short ISC_SHORT;
alias ushort ISC_USHORT;

struct ISC_QUAD
{
        ISC_LONG gds_quad_high;
        ISC_ULONG gds_quad_low;
}

struct XSQLVAR
{
        ISC_SHORT sqltype;
        ISC_SHORT sqlscale;
        ISC_SHORT sqlsubtype;
        ISC_SHORT sqllen;
        ISC_SCHAR * sqldata;
        ISC_SHORT * sqlind;
        ISC_SHORT sqlname_length;
        ISC_SCHAR sqlname[32];
        ISC_SHORT relname_length;
        ISC_SCHAR relname[32];
        ISC_SHORT ownname_length;
        ISC_SCHAR ownname[32];
        ISC_SHORT aliasname_length;
        ISC_SCHAR aliasname[32];
}

const SQLDA_VERSION1 = 1;

struct XSQLDA
{
        ISC_SHORT ver;
        ISC_SCHAR sqldaid[8];
        ISC_LONG  sqldabc;
        ISC_SHORT sqln;
        ISC_SHORT sqld;
        XSQLVAR sqlvar[1];
}

const isc_dpb_version1 = 1;
const isc_dpb_user_name = 28;
const isc_dpb_password = 29;
const isc_dpb_address = 1;

const DSQL_close = 1;
const DSQL_drop = 2;
const DSQL_unprepare = 4;

alias void * FB_API_HANDLE;
alias FB_API_HANDLE isc_db_handle;
alias FB_API_HANDLE isc_blob_handle;
alias FB_API_HANDLE isc_stmt_handle;
alias FB_API_HANDLE isc_tr_handle;

const SQL_TEXT = 452;
const SQL_VARYING = 448;
const SQL_SHORT = 500;
const SQL_LONG = 496;
const SQL_FLOAT = 482;
const SQL_DOUBLE = 480;
const SQL_D_FLOAT = 530;
const SQL_TIMESTAMP = 510;
const SQL_BLOB = 520;
const SQL_ARRAY = 540;
const SQL_QUAD = 550;
const SQL_TYPE_TIME = 560;
const SQL_TYPE_DATE = 570;
const SQL_INT64 = 580;
const SQL_NULL = 32766;

const SQL_DATE = SQL_TIMESTAMP;

const SQL_DIALECT_V5 = 1;
const SQL_DIALECT_V6_TRANSITION = 2;
const SQL_DIALECT_V6 = 3;
const SQL_DIALECT_CURRENT = SQL_DIALECT_V6;

alias int ISC_DATE;
alias uint ISC_TIME;

struct ISC_TIMESTAMP
{
        ISC_DATE timestamp_date;
        ISC_TIME timestamp_time;
}

struct tm
{
        int tm_sec;
        int tm_min;
        int tm_hour;
        int tm_mday;
        int tm_mon;
        int tm_year;
        int tm_wday;
        int tm_yday;
        int tm_isdst;
}

const isc_segstr_eof = 335544367L;

version(DigitalMars)
{
        extern(C)
        {
ISC_STATUS isc_attach_database(ISC_STATUS *, short, const ISC_SCHAR *, isc_db_handle *, short, const ISC_SCHAR *);
                ISC_STATUS isc_print_status(const ISC_STATUS *);
                ISC_STATUS isc_detach_database(ISC_STATUS *, isc_db_handle *);

ISC_STATUS isc_start_transaction(ISC_STATUS *, isc_tr_handle *, short, ...); ISC_STATUS isc_commit_transaction(ISC_STATUS *, isc_tr_handle *); ISC_STATUS isc_rollback_transaction(ISC_STATUS *, isc_tr_handle *);

ISC_STATUS isc_dsql_allocate_statement(ISC_STATUS *, isc_db_handle *, isc_stmt_handle *); ISC_STATUS isc_dsql_alloc_statement2(ISC_STATUS *, isc_db_handle *, isc_stmt_handle *);

ISC_STATUS isc_dsql_describe(ISC_STATUS *, isc_stmt_handle *, ushort, XSQLDA *); ISC_STATUS isc_dsql_describe_bind(ISC_STATUS *, isc_stmt_handle *, ushort, XSQLDA *); ISC_STATUS isc_dsql_execute(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const XSQLDA*); ISC_STATUS isc_dsql_execute2(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const XSQLDA *, const XSQLDA *); ISC_STATUS isc_dsql_execute_immediate(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, ushort, const ISC_SCHAR *, ushort, const XSQLDA *); ISC_STATUS isc_dsql_fetch(ISC_STATUS *, isc_stmt_handle *, ushort, const XSQLDA *);
                ISC_STATUS isc_dsql_finish(isc_db_handle *);
ISC_STATUS isc_dsql_free_statement(ISC_STATUS *, isc_stmt_handle *, ushort); ISC_STATUS isc_dsql_prepare(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const ISC_SCHAR *, ushort, XSQLDA *);

                ISC_LONG fb_interpret(ISC_SCHAR *, uint, const ISC_STATUS **);
ISC_STATUS isc_open_blob(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, isc_blob_handle *, ISC_QUAD *); ISC_STATUS isc_open_blob2(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, isc_blob_handle *, ISC_QUAD *, ISC_USHORT, const ISC_UCHAR *); ISC_STATUS isc_get_segment(ISC_STATUS *, isc_blob_handle *, ushort *, ushort, ISC_SCHAR *);
                ISC_STATUS isc_close_blob(ISC_STATUS *, isc_blob_handle *);

                void isc_decode_sql_date(const ISC_DATE *, void *);
                void isc_decode_sql_time(const ISC_TIME *, void *);
                void isc_decode_timestamp(const ISC_TIMESTAMP *, void *);
        }
}
else
{
        extern(Windows)
        {
ISC_STATUS isc_attach_database(ISC_STATUS *, short, const ISC_SCHAR *, isc_db_handle *, short, const ISC_SCHAR *);
                ISC_STATUS isc_print_status(const ISC_STATUS *);
                ISC_STATUS isc_detach_database(ISC_STATUS *, isc_db_handle *);

ISC_STATUS isc_start_transaction(ISC_STATUS *, isc_tr_handle *, short, ...); ISC_STATUS isc_commit_transaction(ISC_STATUS *, isc_tr_handle *); ISC_STATUS isc_rollback_transaction(ISC_STATUS *, isc_tr_handle *);

ISC_STATUS isc_dsql_allocate_statement(ISC_STATUS *, isc_db_handle *, isc_stmt_handle *); ISC_STATUS isc_dsql_alloc_statement2(ISC_STATUS *, isc_db_handle *, isc_stmt_handle *);

ISC_STATUS isc_dsql_describe(ISC_STATUS *, isc_stmt_handle *, ushort, XSQLDA *); ISC_STATUS isc_dsql_describe_bind(ISC_STATUS *, isc_stmt_handle *, ushort, XSQLDA *); ISC_STATUS isc_dsql_execute(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const XSQLDA*); ISC_STATUS isc_dsql_execute2(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const XSQLDA *, const XSQLDA *); ISC_STATUS isc_dsql_execute_immediate(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, ushort, const ISC_SCHAR *, ushort, const XSQLDA *); ISC_STATUS isc_dsql_fetch(ISC_STATUS *, isc_stmt_handle *, ushort, const XSQLDA *);
                ISC_STATUS isc_dsql_finish(isc_db_handle *);
ISC_STATUS isc_dsql_free_statement(ISC_STATUS *, isc_stmt_handle *, ushort); ISC_STATUS isc_dsql_prepare(ISC_STATUS *, isc_tr_handle *, isc_stmt_handle *, ushort, const ISC_SCHAR *, ushort, XSQLDA *);

                ISC_LONG fb_interpret(ISC_SCHAR *, uint, const ISC_STATUS **);
ISC_STATUS isc_open_blob(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, isc_blob_handle *, ISC_QUAD *); ISC_STATUS isc_open_blob2(ISC_STATUS *, isc_db_handle *, isc_tr_handle *, isc_blob_handle *, ISC_QUAD *, ISC_USHORT, const ISC_UCHAR *); ISC_STATUS isc_get_segment(ISC_STATUS *, isc_blob_handle *, ushort *, ushort, ISC_SCHAR *);
                ISC_STATUS isc_close_blob(ISC_STATUS *, isc_blob_handle *);

                void isc_decode_sql_date(const ISC_DATE *, void *);
                void isc_decode_sql_time(const ISC_TIME *, void *);
                void isc_decode_timestamp(const ISC_TIMESTAMP *, void *);
        }
}

int main(string [] args)
{
        string server = "suporte-pc";
        string user_name = "SYSDBA";
        string user_password = "masterkey";

        ISC_SCHAR [] dpbarray;

dpbarray.length = 7 + server.length + user_name.length + user_password.length;

        ISC_SCHAR * dpb = dpbarray.ptr;

        ISC_SCHAR * dpb_buffer = dpb;

        * dpb_buffer++ = isc_dpb_version1;

        * dpb_buffer++ = isc_dpb_password;
        * dpb_buffer++ = cast(ISC_SCHAR) user_password.length;

        for (auto p = user_password.ptr; * p;)
        {
                * dpb_buffer++ = * p++;
        }

        * dpb_buffer++ = isc_dpb_user_name;
        * dpb_buffer++ = cast(ISC_SCHAR) user_name.length;

        for(auto p = user_name.ptr; * p;)
        {
                * dpb_buffer++ = * p++;
        }

        * dpb_buffer++ = isc_dpb_address;
        * dpb_buffer++ = cast(ISC_SCHAR) server.length;

        for(auto p = cast(ISC_SCHAR *) server.ptr; * p;)
        {
                * dpb_buffer++ = * p++;
        }

        auto dpb_length = cast(short) (dpb_buffer - dpb);

        isc_db_handle handle = null;

auto status = cast(ISC_STATUS *) GC.malloc(ISC_STATUS.sizeof * ISC_STATUS_LENGTH);

if(isc_attach_database(status, 0, "C:\\FIREBIRD.FDB", & handle, dpb_length, dpb))
        {
                isc_print_status(status);

                return 1;
        }

        isc_tr_handle trans = null;

        if(isc_start_transaction(status, & trans, 1, & handle, 0, null))
        {
                isc_print_status(status);

                return 1;
        }

        isc_stmt_handle stmt = null;

        if(isc_dsql_allocate_statement(status, & handle, & stmt))
    {
                isc_print_status(status);

                return 1;
        }

        auto sqlda = cast(XSQLDA *) GC.malloc(XSQLDA.sizeof);

        sqlda.ver = SQLDA_VERSION1;
        sqlda.sqln = 1;

if(isc_dsql_prepare(status, & trans, & stmt, 0, "SELECT * FROM test", SQL_DIALECT_V6, sqlda))
        {
                isc_print_status(status);

                return 1;
        }

        if(isc_dsql_describe(status, & stmt, 1, sqlda))
        {
                isc_print_status(status);

                return 1;
        }

        auto num_cols = sqlda.sqld;

        if(sqlda.sqld > sqlda.sqln)
        {
                auto n = sqlda.sqld;

                GC.free(sqlda);

sqlda = cast(XSQLDA *) GC.malloc(XSQLDA.sizeof + (n - 1) * XSQLVAR.sizeof);

                sqlda.sqln = n;
                sqlda.ver = SQLDA_VERSION1;

                if(isc_dsql_describe(status, & stmt, 1, sqlda))
                {
                        isc_print_status(status);

                        return 1;
                }

                num_cols = sqlda.sqld;
        }

        auto sqlvar = cast(XSQLVAR *) sqlda.sqlvar;
        ISC_SHORT sqlind;

    for(auto i = 0; i < num_cols; i++)
    {
sqlvar[i].sqldata = cast(ISC_SCHAR *) GC.malloc(sqlvar[i].sqllen); sqlvar[i].sqlind = cast(ISC_SHORT *) GC.malloc(ISC_SHORT.sizeof);
    }

        if(isc_dsql_execute(status, & trans, & stmt, 1, sqlda))
        {
                isc_print_status(status);

                return 1;
        }

        while(isc_dsql_fetch(status, & stmt, 1, sqlda) == 0)
        {
                for(auto i = 0; i < num_cols; i++)
                {
                        switch(sqlvar[i].sqltype & 0xFFFFFFFE)
                        {
                                case SQL_TEXT:
                                        sqlvar[i].sqldata[sqlvar[i].sqllen] = 0;

                                        writef("\t%s", 
to!(string)(sqlvar[i].sqldata));
                                break;

                                case SQL_VARYING:
                                        sqlvar[i].sqldata[sqlvar[i].sqllen + 2] 
= 0;

                                        writef("\t%s", 
to!(string)(sqlvar[i].sqldata + 2));
                                break;

                                case SQL_INT64:
                                        printf("\t%d", * cast(long *) 
sqlvar[i].sqldata);
                                break;

                                case SQL_SHORT:
                                        printf("\t%d", * cast(short *) 
sqlvar[i].sqldata);
                                break;

                                case SQL_LONG:
                                        printf("\t%d", * cast(int *) 
sqlvar[i].sqldata);
                                break;

                                case SQL_D_FLOAT:
                                case SQL_FLOAT:
                                        printf("\t%f", * cast(float *) 
sqlvar[i].sqldata);
                                break;

                                case SQL_DOUBLE:
                                        printf("\t%lf", * cast(double *) 
sqlvar[i].sqldata);
                                break;

                                case SQL_TIMESTAMP:
                                        tm timestamp;

isc_decode_timestamp(cast(const ISC_TIMESTAMP *) sqlvar[i].sqldata, & timestamp);

printf("\t%d/%d/%d %d:%d:%d", timestamp.tm_year + 1900, timestamp.tm_mon + 1, timestamp.tm_mday, timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);
                                break;

                                case SQL_TYPE_DATE:
                                        tm date;

isc_decode_sql_date(cast(const ISC_DATE *) sqlvar[i].sqldata, & date);

printf("\t%d/%d/%d", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday);
                                break;

                                case SQL_TYPE_TIME:
                                        tm time;

isc_decode_sql_time(cast(const ISC_TIME *) sqlvar[i].sqldata, & time);

                                        printf("\t%d:%d:%d", time.tm_hour, 
time.tm_min, time.tm_sec);
                                break;

                                case SQL_BLOB:
                                        isc_blob_handle blob_handle = null;

if(isc_open_blob(status, & handle, & trans, & blob_handle, cast(ISC_QUAD *) sqlvar[i].sqldata))
                                        {
                                                isc_print_status(status);

                                                return 1;
                                        }

                                        ISC_SCHAR buffer[80];
                                        ushort len;

while(isc_get_segment(status, & blob_handle, & len, 80, buffer.ptr) != isc_segstr_eof)
                                        {
                                        }

                                        if(isc_close_blob(status, & 
blob_handle))
                                        {
                                                isc_print_status(status);

                                                return 1;
                                        }

                                        //buffer[len] = 0;

                                        writef("\t%d:%s", len, 
to!(string)(buffer.ptr));
                                break;

                                default:
                                break;
                        }
                }

                putchar('\n');
        }

    for(auto i = 0; i < num_cols; i++)
    {
                GC.free(sqlvar[i].sqldata);
                GC.free(sqlvar[i].sqlind);
        }

        GC.free(sqlda);

        if(isc_dsql_free_statement(status, & stmt, DSQL_drop))
        {
                isc_print_status(status);

                return 1;
        }

        if(isc_commit_transaction(status, & trans))
        {
                isc_print_status(status);

                return 1;
        }

    if(isc_detach_database(status, & handle))
        {
                isc_print_status(status);

                return 1;
        }

        GC.free(status);

        return 0;
}
[/code]

Compiling with the GDC, the code executes normally (listing the registry database), but compiling the code with DMD, by executing:

[code]
object.Error: Access Violation
----------------
0x00415B3C
0x004159C7
0x77776299 in RtlRaiseStatus
0x7777626B in RtlRaiseStatus
0x777760F7 in KiUserExceptionDispatcher
0x77783327 in RtlTryEnterCriticalSection
0x77783352 in RtlTryEnterCriticalSection
0x77775B0C in NtWaitForSingleObject
0xFFFFFFFF
----------------
[/code]

The DMD used is 2.060 and the GDC to GCC 4.6.1. Here is how I am compiling the code:

dmd main.d fbclient.lib
gdc main.d -o main.exe -lfbclient_ms

At GDC, we used the library "fbclient_ms.lib" that comes with the default installation of Firebird, and "fbclient.lib" used in DMD was obtained with:

implib fbclient.lib fbclient.dll

What can this be?

Reply via email to