Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Zugriff auf MySQL ohne Komponenten mit Delphi XE2 (https://www.delphipraxis.net/163514-zugriff-auf-mysql-ohne-komponenten-mit-delphi-xe2.html)

Ykcim 1. Okt 2011 21:26

Datenbank: MySQL • Version: 5 • Zugriff über: mysql.pas

Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Hallo Zusammen,

ich habe bislang auf den MySQL ohne Komponenten zugegriffen, mit dem nachfolgenden Code:

Delphi-Quellcode:
procedure connect;
var Datei: TextFile;
    MyString: String;
begin
  AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
  Reset(Datei);
  try
    ReadLn(Datei, MyString);
    host := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
    ReadLn(Datei, MyString);
    User := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
    ReadLn(Datei, MyString);
    Pass := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
    ReadLn(Datei, MyString);
    DB := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
  finally
    CloseFile(Datei);
  end;
  _myCon := mysql_init(nil);
  if _mycon=nil then
  begin
    showmessage('Nicht genügend freier Speicher!');
    Exit;
  end;
  if mysql_real_connect(_mycon, host, user, pass,db, 3306, nil,0)=nil then
  begin
    showmessage('Die Verbindung konnte nicht hergestellt werden! Ursache:' + mysql_error(_mycon));
    exit;
  end;
end;
Das funktionierte auch wunderbar und zuverlässig. Jetzt versuche ich gerade den Umstieg von TurboDelphi auf Delphi xe2 starter. Und das ist das Problem. Ich bekomme keine Verbindung mehr zu der Datenbank.

An dieser Stelle im Code macht er einen Fehler:
Delphi-Quellcode:
_myCon := mysql_init(nil);

Hat jemand eine Idee, woran das liegen kann? Die Datenbank hat sich nicht geändert, es muss mit Delphi xe2 zusammenhängen.

Vielen Dank
Ykcim

mkinzler 1. Okt 2011 21:47

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Zitat:

An dieser Stelle im Code macht er einen Fehler:
Welcher?

Ykcim 1. Okt 2011 21:51

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Delphi-Quellcode:
procedure connect;
var Datei: TextFile;
     MyString: String;
begin
   AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
   Reset(Datei);
   try
     ReadLn(Datei, MyString);
     host := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
     ReadLn(Datei, MyString);
     User := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
     ReadLn(Datei, MyString);
     Pass := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
     ReadLn(Datei, MyString);
     DB := Pchar(copy(MyString, pos(':', MyString)+1, length(MyString)));
   finally
     CloseFile(Datei);
   end;

  //AN DIESER STELLE
   _myCon := mysql_init(nil);


   if _mycon=nil then
   begin
     showmessage('Nicht genügend freier Speicher!');
     Exit;
   end;
   if mysql_real_connect(_mycon, host, user, pass,db, 3306, nil,0)=nil then
   begin
     showmessage('Die Verbindung konnte nicht hergestellt werden! Ursache:' + mysql_error(_mycon));
     exit;
   end;
end;

Ich bekomme einfach nur eine Meldung, dass die Verbindung nicht hergestellt werden kann...

geskill 1. Okt 2011 22:03

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Sieht wie ein Unicode/Ansi Problem aus. TurboDelphi benutzt ja standardmäßig AnsiString.

Delphi-Quellcode:
procedure connect;
var Datei: TextFile;
      MyString: Ansistring;
begin
    AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
    Reset(Datei);
    try
      ReadLn(Datei, MyString);
      host := PAnsiChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
      ReadLn(Datei, MyString);
      User := PAnsiChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
      ReadLn(Datei, MyString);
      Pass := PAnsiChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
      ReadLn(Datei, MyString);
      DB := PAnsiChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
    finally
      CloseFile(Datei);
    end;

    //...

EDIT:
Quatsch der Fehler kommt ja schon vorher. Denke mal du hast dann die neue mysql.pas (Version 2011-09-15)
für XE2. Im Header steht da folgendes:

Zitat:

procedure mysql_server_end;
{ "Jeremiah Gowdy" <jgowdycox.net> wrote on 10/11/2005 03:08:40 AM:
The Windows DLL is thread safe. You do not have to call my_init()
and my_thread_init() because Windows DLLs receive events when they
are attached to a new process and when they are attached to a new
thread in a process. This is one of the nicer features of Windows
shared libraries. Other than that, you don't have to do anything
special. I am a heavy user of libmysql under Win32. You simply
mysql_init() your MYSQL struct, and then mysql_real_connect() and
you're ready to mysql_query().
New on February 17, 2009 02:27AM: This is true until 5.0.77 -
since this version this nice feature ist removed from dll.c.
To obtain the previous behavior (DLL initialization code will be
called), set the LIBMYSQL_DLLINIT environment variable to
any value. http://forums.mysql.com/read.php?3,248207,248207 }
function mysql_thread_init: my_bool; //called internal by mysql_init or mysql_server_init
{ New on February 17, 2009 02:27AM: Since 5.0.77 mysql_thread_end
is not called during DllMain() if the LIBMYSQL_DLLINIT environment variable is
not set. So it is necessary to call mysql_thread_end to avoid memory leaks. }
procedure mysql_thread_end;
Aber das wäre ja nur der Fall für Threadsicherheit.

Aber du hast ja nicht die Unit von TurboDelphi für XE2 benutzt, weil da brauchst du denke ich
die neue welche extra dafür kompatibel gemacht wurde.

Ykcim 1. Okt 2011 22:23

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Vielen Dank für die Antwort!

Ich habe den Code jetzt soweit geändert:

Delphi-Quellcode:
var
  Form1: TForm1;
  _myCon: PMYSQL;
  host, user, pass, db: PChar;
  ErrorCode: Integer;
  MySQLRes: PMYSQL_RES;
  MySQLRow: PMYSQL_ROW;
  AffectedRows: Int64;
  Field: PMYSQL_FIELD;

//...

procedure connect;
var Datei: TextFile;
       MyString: Ansistring;
begin
     AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
     Reset(Datei);
     try
       ReadLn(Datei, MyString);
       host := PChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
       ReadLn(Datei, MyString);
       User := PChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
       ReadLn(Datei, MyString);
       Pass := PChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
       ReadLn(Datei, MyString);
       DB := PChar(copy(MyString, pos(':', MyString)+1, length(MyString)));
     finally
       CloseFile(Datei);
     end;
  end;
{73}  _myCon := mysql_init(nil);
  if _mycon=nil then
  begin
    showmessage('Nicht genügend freier Speicher!');
{78}    Exit;
  end;
{80}  if mysql_real_connect(_mycon, host, user, pass,db, 3306, nil,0)=nil then
  begin
    showmessage('Die Verbindung konnte nicht hergestellt werden! Ursache:' + mysql_error(_mycon));
    exit;
{83}  end;
end;

Leider habe ich es jetzt noch nicht geschafft, wieder zu kompilieren, da ich diverse Fehler bekomme:
Zitat:

[DCC Fehler] Unit1.pas(73): E2029 Deklaration erwartet, aber Bezeichner '_myCon' gefunden
[DCC Fehler] Unit1.pas(78): E2029 '.' erwartet, aber ';' gefunden
[DCC Fehler] Unit1.pas(80): E2004 Bezeichner redefiniert: 'Finalization'
[DCC Warnung] Unit1.pas(83): W1011 Text hinter dem abschließenden 'END.' - wird vom Compiler ignoriert
[DCC Fehler] Unit1.pas(13): E2065 Ungenügende Forward- oder External-Deklaration: 'TForm1.Button1Click'
[DCC Fataler Fehler] Project1.dpr(5): F2063 Verwendete Unit 'Unit1.pas' kann nicht compiliert werden
Misslungen
Verstrichene Zeit: 00:00:00.2
Könnt Ihr mir sagen, wo diese Fehler liegen?

Vielen Dank
Ykcim

Ykcim 1. Okt 2011 22:45

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Vergesst das!

Ich habe mir die neuste mysql.pas heruntergeldaen, aber da bekomme ich Kompilierungsfehler...

Versuche es nachzuvollziehen.

wurzelzwerg 2. Okt 2011 09:49

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Vor {73} ist ein end zu viel.

samso 2. Okt 2011 11:31

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Die mysql-Funktionen arbeiten intern mit AnsiStrings bzw. UFT8Strings.
Delphi-Quellcode:
host, user, pass, db: PChar;
deklariert aber Unicode-Strings.

Delphi-Quellcode:
var
   Form1: TForm1;
   _myCon: PMYSQL;
   host, user, pass, db: AnsiString;
   ErrorCode: Integer;
   MySQLRes: PMYSQL_RES;
   MySQLRow: PMYSQL_ROW;
   AffectedRows: Int64;
   Field: PMYSQL_FIELD;

//...

procedure connect;
var Datei: TextFile;
        MyString: Ansistring;
begin
    AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
    Reset(Datei);
    try
      ReadLn(Datei, MyString);
      host := copy(MyString, pos(':', MyString)+1, MaxInt);
      ReadLn(Datei, MyString);
      User := copy(MyString, pos(':', MyString)+1, MaxInt);
      ReadLn(Datei, MyString);
      Pass := copy(MyString, pos(':', MyString)+1, MaxInt);
      ReadLn(Datei, MyString);
      DB := copy(MyString, pos(':', MyString)+1, MaxInt);
    finally
      CloseFile(Datei);
    end;
   _myCon := mysql_init(nil);
   if _mycon=nil then
   begin
     showmessage('MySql-Verbindung konnte nicht initialisiert werden!');
     Exit;
   end;
  if mysql_real_connect(_mycon, PAnsiChar(host), PAnsiChar(user), PAnsiChar(pass),PAnsiChar(db), 3306, nil,0)=nil then
   begin
     showmessage('Die Verbindung konnte nicht hergestellt werden! Ursache:' + mysql_error(_mycon));
     exit;
  end;
end;
Tip 1: Seit einigen Jahren lädt die mysql.pas die DLL nicht mehr automatisch (per Compilerschalter kann dieses Verhalten jedoch geändert werden). Statt dessen sollte die DLL per libmysql_fast_load(nil) geladen werden.
Tip 2: Da der interne Aufbau des Records TMYSQL_FIELD von der verwendeten Version der LibMySql.dll abhängt, sollte man den direkten Zugriff auf dieses Record vermeiden und stattdessen die Funktionen "mysql_field_type", "mysql_field_flag", "mysql_field_length", "mysql_field_name", "mysql_field_tablename", "mysql_field_default" usw. benutzen. Diese Funktionen erlauben einen Zugriff auf die Feldparameter unabhängig von der beim Benutzer/Kunden installierten Version der LibMySql.dll.

Ykcim 18. Okt 2011 10:42

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Hallo Zusammen,

ich bin leider noch nicht wirklich weitergekommen mit meinen Bemühungen, mit Delphi xe2 starter auf eine MySQL-Datenbank zugreifen zu können.
Das ganze soll ohne Komponenten möglich sein.
Vielleicht hat jemand das Thema schon gelöst - ich habe aber noch nichts gefunden...
Angedacht sind drei Prozeduren/Funktionen: Connect, ExecQuery und disconnect.
Nachstehend was ich bis hierhin gefrickelt habe, in der Hoffnung, dass wir es hier dann zum Laufen bringen...

KOPF:
Delphi-Quellcode:
unit DBconnectUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids,
  Vcl.StdCtrls, mysql;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StringGrid1: TStringGrid;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  TRows = array of array of string; // [Cols, Rows]
  TCols = array of string;

var
  Form1: TForm1;
  LibHandle: PMYSQL;
  mySQL_Res: PMYSQL_RES;
  ErrorCode: Integer;
  ColCount: integer;
  AffectedRows: Int64;
  host, User, Pass, DB: Ansistring;

implementation

{$R *.dfm}


CONNECT:
Delphi-Quellcode:
procedure connect;
var
  MYSQL_ROW: PMYSQL_ROW;
  Datei: TextFile;
  MyString: String;
begin
  libmysql_fast_load(nil);
  AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
  Reset(Datei);
  try
    ReadLn(Datei, MyString);
    host := copy(MyString, pos(':', MyString)+1, length(MyString));
    ReadLn(Datei, MyString);
    User := copy(MyString, pos(':', MyString)+1, length(MyString));
    ReadLn(Datei, MyString);
    Pass := copy(MyString, pos(':', MyString)+1, length(MyString));
    ReadLn(Datei, MyString);
    DB := copy(MyString, pos(':', MyString)+1, length(MyString));
  finally
    CloseFile(Datei);
  end;
  if mySQL_Res<>nil
  then
    mysql_free_result(mySQL_Res);
  mySQL_Res := nil;
  if LibHandle<>nil
  then begin
    mysql_close(LibHandle);
    LibHandle := nil;
  end;
  LibHandle := mysql_init(nil);
  if LibHandle=nil
  then
    raise Exception.Create('mysql_init failed');
  if (mysql_real_connect(LibHandle,
                         PAnsiChar(AnsiString(Host)),
                         PAnsiChar(AnsiString(User)),
                         PAnsiChar(AnsiString(Pass)),
                         PAnsiChar(AnsiString(DB)),
                         3306, nil, 0)=nil)
  then
    raise Exception.Create(mysql_error(LibHandle));
end;


EXECQUERY:
Delphi-Quellcode:
function ExecQuery(const Datenbank, query: string; var Cols: TCols;
                   var Rows: TRows): Boolean;
var
  j, i, field_count, row_count: Integer;
  mySQL_Field: PMYSQL_FIELD;
  tablename: String;
  MYSQL_ROW: PMYSQL_ROW;
begin
   SetLength(Cols, 0);
   // Datenbank auswählen
   ErrorCode := mysql_select_db(LibHandle, PAnsiChar(AnsiString(Datenbank)));
   if ErrorCode = 0 then
   begin
     // Query ausführen
   if mysql_real_query(LibHandle, PAnsiChar(query), Length(query))<>0
    then begin
      raise Exception.Create(mysql_error(LibHandle));
      exit;
     end
     else
     begin
       // Query speichern
       mySQL_Res := mysql_store_result(LibHandle);
       if mySQL_Res<>nil
       then begin
         // zurückgelieferte Anzahl der Spalten
         ColCount := mysql_num_fields(mySQL_Res);
         SetLength(Cols, ColCount);
         SetLength(Rows, ColCount, 0);
         SetLength(Cols, ColCount);
         // Spalten-Array füllen
         for i := 0 to ColCount - 1 do
         begin
           mySQL_Field := mysql_fetch_field_direct(mySQL_Res, i);
           Cols[i] := mysql_field_name(mySQL_Field);
         end;
         // Anzahl der betroffenen Zeilen ermitteln
         AffectedRows := mysql_num_rows(mySQL_Res);
         SetLength(Rows, ColCount, AffectedRows);
         // neu ->
         // Zeilen-array füllen
         // alle Zeilen ...
         for j := 0 to AffectedRows - 1 do
         begin
           // ... werden eingelesen
           MySQL_Row := mysql_fetch_row(mySQL_Res);
           // alle Spalten ...
           for i := 0 to ColCount - 1 do
           begin
             // ... werden in Rows[] übertragen
             Rows[i, j] := MySQL_Row[i];

           end;
         end;
         // gespeicherte Abfrage wieder freigeben
         mysql_free_result(MySQL_Res);
       end
     end
   end;
   result := ErrorCode = 0;
end;


DISCONNECT:
Delphi-Quellcode:
procedure disconnect;
begin
  mysql_close(LibHandle);
  LibHandle := nil;
  if mySQL_Res<>nil
  then
    mysql_free_result(mySQL_Res);
  if libmysql_status=LIBMYSQL_READY
  then
    mysql_close(LibHandle);
  libmysql_free;
end;


AUFRUF:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  query: Ansistring;
  Cols: TCols;
  Rows: TRows;
begin
  query:='select * from as400';
  connect;
  ExecQuery(db, query, Cols, Rows);
  disconnect;
  FillGrid(StringGrid1, Cols, Rows);
end;

Im Moment passiert Folgendes:
Beim ausführen bekomme ich eine Fehlermeldung, dass ich einen Fehler in meinem SQL-Syntax hätte. Das ist nicht der Fall, denn wenn ich den Wert aus der Variablen "query" in dem MySQL-Server direkt ausführe funktioniert es...

Der Fehler wird in der MySQL.pas erzeugt, in dieser Prozedure:
Delphi-Quellcode:
function mysql_error(_mysql: PMYSQL): PAnsiChar;
begin
  if @_mysql_error=nil
  then
    LoadProcAddress(@_mysql_error, 'mysql_error');
  Result := _mysql_error(_mysql);
end;

Die Fehlermeldung lautet:
Zugriffsverletzung bei FFFEB4E8 und Zugriff auf FFFEB4E8

Delphi-Übersetzung:
Im Projekt DBconnect ist eine Exception der Klasse Exception mit der Meldung 'You have an error in your MySQL-Syntax; check manual ...


Ich bewege mich mit dieser Sache auf zu dünnem Eis und bin auf Hilfe angewiesen. Kann mir jemand helfen, wie ich auf diese Weise die Verbindung zu meinem MySQL-Server hinbekomme?

Vielen Dank im Voraus

Ykcim

Ykcim 18. Okt 2011 15:14

AW: Zugriff auf MySQL ohne Komponenten mit Delphi XE2
 
Hallo Zusammen,

den genannten Fehler konnte ich beheben: Ich musste die Variable query und Datenbank von string auf AnsiString ändern.

Delphi-Quellcode:
function ExecQuery(const Datenbank, query: Ansistring; var Cols: TCols;
                   var Rows: TRows): Boolean;

Die Procedure disconnect ist wie folgt angepasst, aber da glaube ich, dass noch nicht alles rund läuft. Kommentare dazu sind willkommen.

Delphi-Quellcode:
procedure disconnect;
begin
  mysql_close(LibHandle);
  LibHandle := nil;
  mySQL_Res := nil;
  libmysql_free;
end;

Ykcim


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz