May 20, 2004
Can anybody please tell me why the following code behaves the way it does. I'm working on Windows and trying to hook into the Firebird database library (version 1.5). The code I have included is supposed to try and create a new database file. When I execute this for the first time (i.e. when the database file does not exist) it creates the database and the output seems to indicate that it was successful but it tells me there was an error. When I execute it a second or subsequent time the output seems to say that it should fail the success test but it doesn't.

To get this to work you must have a copy of the fbclient.dll file in the local directory. This is part of a larger piece of code that I am working on but I have cut it to a single file for demonstration purposes. Any ideas?



import std.string;

extern (C) alias long (*execute_immediate)(long *,
                                           void **,
                                           void **,
                                           ushort,
                                           char *,
                                           ushort,
                                           void *);

extern(Windows)
{
   void *LoadLibraryA(char *);
   int FreeLibrary(void *);
   void *GetProcAddress(void *, char *);
}

int main(char[][] arguments)
{
   void *library = LoadLibraryA("fbclient.dll");

   if(!(library is null))
   {
      execute_immediate func = null;

      // Fetch the function reference.
      func = cast(execute_immediate)GetProcAddress(library,
                                                   "isc_dsql_execute_immediate");
      if(!(func is null))
      {
         long[20] status;
         ushort   dialect     = 3;
         void*    database    = null,
                  transaction = null,
                  last        = null;
         char[]   sql         = "CREATE DATABASE \"test.fdb\" USER " ~
                                "\"SYSDBA\" PASSWORD \"masterkey\"";

         func(&status[0], &database, &transaction, 0, toStringz(sql),
              dialect, last);

         printf("Status[0] = %ld, Status[1] = %ld\n", status[0], status[1]);
         if(status[0] == 1 && status[1] > 0)
            printf("ERROR: Database create failed.");
         else
            printf("Database created.\n");
      }
      else
         printf("Failed to load function reference.\n");

      FreeLibrary(library);
   }
   else
      printf("Failed to load fbclient.dll\n");

   return(0);
}

May 20, 2004
A couple of things that may help, one now, and one in general.  Although I don't think I know your error, sorry.

Peter Wood wrote:
> import std.string;
> 
> extern (C) alias long (*execute_immediate)(long *,
>                                            void **,
>                                            void **,
>                                            ushort,
>                                            char *,
>                                            ushort,
>                                            void *);

Changes this to:

extern (C) alias
  long function(long*, void**, void**, ushort, char*, ushort, void*)
  execute_immediate;

As far as I know, C-style function pointer syntax is a no-no in D.  I could be wrong though.

> extern(Windows)
> {
>    void *LoadLibraryA(char *);
>    int FreeLibrary(void *);
>    void *GetProcAddress(void *, char *);
> }
> 
> int main(char[][] arguments)
> {
>    void *library = LoadLibraryA("fbclient.dll");
> 
>    if(!(library is null))
>    {
>       execute_immediate func = null;
> 
>       // Fetch the function reference.
>       func = cast(execute_immediate)GetProcAddress(library,
>                                                    "isc_dsql_execute_immediate");
>       if(!(func is null))
>       {
>          long[20] status;
>          ushort   dialect     = 3;
>          void*    database    = null,
>                   transaction = null,
>                   last        = null;
>          char[]   sql         = "CREATE DATABASE \"test.fdb\" USER " ~
>                                 "\"SYSDBA\" PASSWORD \"masterkey\"";

For sql you could take advantage of D's wysiwyg string literals and implicit concatenation of literals.  Ie, change that line to:
char[] sql         = `CREATE DATABASE "text.fdb"`
                     ` USER "SYSDBA"`
                     ` PASSWORD "masterkey"`;

>          func(&status[0], &database, &transaction, 0, toStringz(sql),
>               dialect, last);
> 
>          printf("Status[0] = %ld, Status[1] = %ld\n", status[0], status[1]);
>          if(status[0] == 1 && status[1] > 0)
>             printf("ERROR: Database create failed.");
>          else
>             printf("Database created.\n");
>       }
>       else
>          printf("Failed to load function reference.\n");
> 
>       FreeLibrary(library);
>    }
>    else
>       printf("Failed to load fbclient.dll\n");
> 
>    return(0);
> }
> 

I really don't see any error in your code itself... but I'm also not personally familiar with Firebird so there might be some quirk that's beyond me.

-C. Sauls
-Invironz