From b54a122fe685021484d83479c7d8e84245ef84e8 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Tue, 21 Aug 2007 16:47:28 +0000 Subject: [PATCH] Fix bug #1757524 "Exporting rather slow when processing large BLOBs" by making use of mysql_real_escape_string() . --- .../zeosdbo/src/component/ZConnection.pas | 5 +++ components/zeosdbo/src/dbc/ZDbcConnection.pas | 6 ++++ components/zeosdbo/src/dbc/ZDbcIntfs.pas | 1 + components/zeosdbo/src/dbc/ZDbcMySql.pas | 16 +++++++++ .../zeosdbo/src/dbc/ZDbcMySqlStatement.pas | 2 +- .../zeosdbo/src/plain/ZPlainMySqlDriver.pas | 32 +++++++++--------- source/helpers.pas | 33 ++++++++++--------- 7 files changed, 62 insertions(+), 33 deletions(-) diff --git a/components/zeosdbo/src/component/ZConnection.pas b/components/zeosdbo/src/component/ZConnection.pas index 08388c49..30d45233 100644 --- a/components/zeosdbo/src/component/ZConnection.pas +++ b/components/zeosdbo/src/component/ZConnection.pas @@ -183,6 +183,7 @@ type function Ping: Boolean; virtual; function GetAffectedRowsFromLastPost: Int64; function GetThreadId: Cardinal; + function GetEscapeString(const Value: string): string; procedure StartTransaction; virtual; procedure Commit; virtual; @@ -364,6 +365,10 @@ begin Result := FConnection.GetThreadId; end; +function TZConnection.GetEscapeString(const Value: string): string; +begin + Result := FConnection.GetEscapeString(Value); +end; {** diff --git a/components/zeosdbo/src/dbc/ZDbcConnection.pas b/components/zeosdbo/src/dbc/ZDbcConnection.pas index 597b4ba2..b92d2e8b 100644 --- a/components/zeosdbo/src/dbc/ZDbcConnection.pas +++ b/components/zeosdbo/src/dbc/ZDbcConnection.pas @@ -176,6 +176,7 @@ type function Ping: Boolean; virtual; function GetAffectedRowsFromLastPost: Int64; virtual; function GetThreadId: Cardinal; virtual; + function GetEscapeString(const Value: string): string; virtual; function GetDriver: IZDriver; function GetMetadata: IZDatabaseMetadata; @@ -803,6 +804,11 @@ begin raise Exception.Create('GetThreadId() is unsupported by this particular DB driver.'); end; +function TZAbstractConnection.GetEscapeString(const Value: string): string; +begin + raise Exception.Create('GetEscapeString() is unsupported by this particular DB driver.'); +end; + {** Gets the parent ZDBC driver. @returns the parent ZDBC driver interface. diff --git a/components/zeosdbo/src/dbc/ZDbcIntfs.pas b/components/zeosdbo/src/dbc/ZDbcIntfs.pas index 83d767e6..cff1e570 100644 --- a/components/zeosdbo/src/dbc/ZDbcIntfs.pas +++ b/components/zeosdbo/src/dbc/ZDbcIntfs.pas @@ -246,6 +246,7 @@ type function Ping: Boolean; function GetAffectedRowsFromLastPost: Int64; function GetThreadId: Cardinal; + function GetEscapeString(const Value: string): string; function GetDriver: IZDriver; function GetMetadata: IZDatabaseMetadata; diff --git a/components/zeosdbo/src/dbc/ZDbcMySql.pas b/components/zeosdbo/src/dbc/ZDbcMySql.pas index 224c4666..0c843f3a 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySql.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySql.pas @@ -127,6 +127,7 @@ type procedure Close; override; function GetAffectedRowsFromLastPost: Int64; override; function GetThreadId: Cardinal; override; + function GetEscapeString(const Value: string): string; override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; @@ -619,6 +620,21 @@ begin Result := FPlainDriver.GetThreadId(FHandle); end; +{** + Escapes a string for usage in SQL queries +} +function TZMySQLConnection.GetEscapeString(const Value: string): string; +var + BufferLen: Integer; + Buffer: PChar; +begin + BufferLen := Length(Value) * 2 + 1; + GetMem(Buffer, BufferLen); + BufferLen := FPlainDriver.GetEscapeString(FHandle, Buffer, PChar(Value), Length(Value)); + Result := BufferToStr(Buffer, BufferLen); + FreeMem(Buffer); +end; + {** Gets a selected catalog name. @return a selected catalog name. diff --git a/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas b/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas index 939963ed..3a528fc8 100644 --- a/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas +++ b/components/zeosdbo/src/dbc/ZDbcMySqlStatement.pas @@ -336,7 +336,7 @@ var begin BufferLen := Length(Value) * 2 + 1; GetMem(Buffer, BufferLen); - BufferLen := FPlainDriver.GetEscapeString(Buffer, PChar(Value), Length(Value)); + BufferLen := FPlainDriver.GetEscapeString(FHandle, Buffer, PChar(Value), Length(Value)); Result := '''' + BufferToStr(Buffer, BufferLen) + ''''; FreeMem(Buffer); end; diff --git a/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas b/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas index 31815aae..c513e6c7 100644 --- a/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas +++ b/components/zeosdbo/src/plain/ZPlainMySqlDriver.pas @@ -198,7 +198,7 @@ type // eof function GetLastErrorCode(Handle: PZMySQLConnect): Integer; function GetLastError(Handle: PZMySQLConnect): PChar; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function FetchField(Res: PZMySQLResult): PZMySQLField; // fetch_field_direct // fetch_fields @@ -393,7 +393,7 @@ type function GetStatInfo(Handle: PZMySQLConnect): PChar; function SetOptions(Handle: PZMySQLConnect; Option: TZMySQLOption; const Arg: PChar): Integer; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PChar; function GetClientInfo: PChar; @@ -513,7 +513,7 @@ type function GetStatInfo(Handle: PZMySQLConnect): PChar; function SetOptions(Handle: PZMySQLConnect; Option: TZMySQLOption; const Arg: PChar): Integer; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PChar; function GetClientInfo: PChar; @@ -633,7 +633,7 @@ type function GetStatInfo(Handle: PZMySQLConnect): PChar; function SetOptions(Handle: PZMySQLConnect; Option: TZMySQLOption; const Arg: PChar): Integer; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PChar; function GetClientInfo: PChar; @@ -763,7 +763,7 @@ type function GetStatInfo(Handle: PZMySQLConnect): PChar; function SetOptions(Handle: PZMySQLConnect; Option: TZMySQLOption; const Arg: PChar): Integer; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PChar; function GetClientInfo: PChar; @@ -894,7 +894,7 @@ type function GetStatInfo(Handle: PZMySQLConnect): PChar; function SetOptions(Handle: PZMySQLConnect; Option: TZMySQLOption; const Arg: PChar): Integer; - function GetEscapeString(StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; + function GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PChar; function GetClientInfo: PChar; @@ -1088,10 +1088,10 @@ begin Result := MYSQL_API.mysql_get_client_info; end; -function TZMySQL320PlainDriver.GetEscapeString(StrTo, StrFrom: PChar; +function TZMySQL320PlainDriver.GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; begin - Result := MYSQL_API.mysql_escape_string(StrTo, StrFrom, Length); + Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end; function TZMySQL320PlainDriver.GetHostInfo(Handle: PZMySQLConnect): PChar; @@ -1580,10 +1580,10 @@ begin Result := MYSQL_API.mysql_get_client_info; end; -function TZMySQL323PlainDriver.GetEscapeString(StrTo, StrFrom: PChar; +function TZMySQL323PlainDriver.GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; begin - Result := MYSQL_API.mysql_escape_string(StrTo, StrFrom, Length); + Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end; function TZMySQL323PlainDriver.GetHostInfo(Handle: PZMySQLConnect): PChar; @@ -2070,10 +2070,10 @@ begin Result := MYSQL_API.mysql_get_client_info; end; -function TZMySQL40PlainDriver.GetEscapeString(StrTo, StrFrom: PChar; +function TZMySQL40PlainDriver.GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; begin - Result := MYSQL_API.mysql_escape_string(StrTo, StrFrom, Length); + Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end; function TZMySQL40PlainDriver.GetHostInfo(Handle: PZMySQLConnect): PChar; @@ -2593,10 +2593,10 @@ begin Result := MYSQL_API.mysql_get_client_info; end; -function TZMySQL41PlainDriver.GetEscapeString(StrTo, StrFrom: PChar; +function TZMySQL41PlainDriver.GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; begin - Result := MYSQL_API.mysql_escape_string(StrTo, StrFrom, Length); + Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end; function TZMySQL41PlainDriver.GetHostInfo(Handle: PZMySQLConnect): PChar; @@ -3117,10 +3117,10 @@ begin Result := MYSQL_API.mysql_get_client_info; end; -function TZMySQL5PlainDriver.GetEscapeString(StrTo, StrFrom: PChar; +function TZMySQL5PlainDriver.GetEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PChar; Length: Cardinal): Cardinal; begin - Result := MYSQL_API.mysql_escape_string(StrTo, StrFrom, Length); + Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end; function TZMySQL5PlainDriver.GetHostInfo(Handle: PZMySQLConnect): PChar; diff --git a/source/helpers.pas b/source/helpers.pas index 9558f620..303aeff8 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -1240,24 +1240,25 @@ end; @return string } function esc(Text: string; ProcessJokerChars: Boolean = false; sql_version: integer = 50000): string; +var + i : Integer; begin - Result := Text; - if sql_version <> SQL_VERSION_ANSI then begin - // Replace single-backslashes with double-backslashes BEFORE - // special characters get escaped using their escape-sequence - // Fixes issue #1648978 "exported sql has \\r\\n instead of \r\n for CRLFs" - Result := StringReplace(Result, '\', '\\', [rfReplaceAll]); - - {NUL} Result := StringReplace(Result, #0, '\0', [rfReplaceAll]); - {BS} Result := StringReplace(Result, #8, '\b', [rfReplaceAll]); - {TAB} Result := StringReplace(Result, #9, '\t', [rfReplaceAll]); - {CR} Result := StringReplace(Result, #13, '\r', [rfReplaceAll]); - {LF} Result := StringReplace(Result, #10, '\n', [rfReplaceAll]); - {EOF} Result := StringReplace(Result, #26, '\Z', [rfReplaceAll]); - - {DQ} Result := StringReplace(Result, '"', '\"', [rfReplaceAll]); + if sql_version = SQL_VERSION_ANSI then begin + // Do a manual iteration + replacing of single quotes, which is much + // faster than StringReplace on text with a large amount of replacements + Result := ''; + for i := 1 to Length(Text) do + begin + if Text[i] = #39 then + Result := Result + #39#39 + else + Result := Result + Text[i]; + end; + end + else begin + // Use the API function mysql_real_escape_string to escape text + Result := Mainform.Childwin.MysqlConn.Connection.GetEscapeString(Text); end; - {SQ} Result := StringReplace(Result, #39, #39#39, [rfReplaceAll]); if ProcessJokerChars then begin