mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-23 02:29:26 +02:00
+ Added simulation of parameters for MySQL
+ Fixed problems with EDatabaseError + Fixed a problem with parameters that are used more then once git-svn-id: trunk@3772 -
This commit is contained in:
parent
06be3aba7d
commit
f36010fc31
13
fcl/db/db.pp
13
fcl/db/db.pp
@ -1576,7 +1576,7 @@ type
|
|||||||
TParamType = (ptUnknown, ptInput, ptOutput, ptInputOutput, ptResult);
|
TParamType = (ptUnknown, ptInput, ptOutput, ptInputOutput, ptResult);
|
||||||
TParamTypes = set of TParamType;
|
TParamTypes = set of TParamType;
|
||||||
|
|
||||||
TParamStyle = (psInterbase,psPostgreSQL);
|
TParamStyle = (psInterbase,psPostgreSQL,psSimulated);
|
||||||
|
|
||||||
TParams = class;
|
TParams = class;
|
||||||
|
|
||||||
@ -1694,6 +1694,7 @@ type
|
|||||||
Function ParseSQL(SQL: String; DoCreate: Boolean): String;
|
Function ParseSQL(SQL: String; DoCreate: Boolean): String;
|
||||||
Function ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle): String; overload;
|
Function ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle): String; overload;
|
||||||
Function ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding): String; overload;
|
Function ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding): String; overload;
|
||||||
|
Function ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding; var ReplaceString : string): String;
|
||||||
Procedure RemoveParam(Value: TParam);
|
Procedure RemoveParam(Value: TParam);
|
||||||
Procedure CopyParamValuesFromDataset(ADataset : TDataset; CopyBound : Boolean);
|
Procedure CopyParamValuesFromDataset(ADataset : TDataset; CopyBound : Boolean);
|
||||||
Property Dataset : TDataset Read GetDataset;
|
Property Dataset : TDataset Read GetDataset;
|
||||||
@ -1868,7 +1869,10 @@ end;
|
|||||||
Procedure DatabaseError (Const Msg : String; Comp : TComponent);
|
Procedure DatabaseError (Const Msg : String; Comp : TComponent);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Raise EDatabaseError.CreateFmt('%s : %s',[Comp.Name,Msg]);
|
if assigned(Comp) then
|
||||||
|
Raise EDatabaseError.CreateFmt('%s : %s',[Comp.Name,Msg])
|
||||||
|
else
|
||||||
|
DatabaseError(Msg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of Const);
|
Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of Const);
|
||||||
@ -1880,7 +1884,10 @@ end;
|
|||||||
Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of const;
|
Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of const;
|
||||||
Comp : TComponent);
|
Comp : TComponent);
|
||||||
begin
|
begin
|
||||||
Raise EDatabaseError.CreateFmt(Format('%s : %s',[Comp.Name,Fmt]),Args);
|
if assigned(comp) then
|
||||||
|
Raise EDatabaseError.CreateFmt(Format('%s : %s',[Comp.Name,Fmt]),Args)
|
||||||
|
else
|
||||||
|
DatabaseErrorFmt(Fmt, Args);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function ExtractFieldName(Const Fields: String; var Pos: Integer): String;
|
Function ExtractFieldName(Const Fields: String; var Pos: Integer): String;
|
||||||
|
@ -153,21 +153,32 @@ end;
|
|||||||
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean): String;
|
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean): String;
|
||||||
|
|
||||||
var pb : TParamBinding;
|
var pb : TParamBinding;
|
||||||
|
rs : string;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result := ParseSQL(SQL,DoCreate,psInterbase, pb);
|
Result := ParseSQL(SQL,DoCreate,psInterbase, pb, rs);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle): String;
|
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle): String;
|
||||||
|
|
||||||
var pb : TParamBinding;
|
var pb : TParamBinding;
|
||||||
|
rs : string;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result := ParseSQL(SQL,DoCreate,ParameterStyle,pb);
|
Result := ParseSQL(SQL,DoCreate,ParameterStyle,pb, rs);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding): String;
|
||||||
|
|
||||||
|
var pb : TParamBinding;
|
||||||
|
rs : string;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := ParseSQL(SQL,DoCreate,ParameterStyle,pb, rs);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding): String;
|
Function TParams.ParseSQL(SQL: String; DoCreate: Boolean; ParameterStyle : TParamStyle; var ParamBinding: TParambinding; var ReplaceString : string): String;
|
||||||
|
|
||||||
type
|
type
|
||||||
// used for ParamPart
|
// used for ParamPart
|
||||||
@ -189,12 +200,16 @@ var
|
|||||||
ParamPart:array of TStringPart; // describe which parts of buf are parameters
|
ParamPart:array of TStringPart; // describe which parts of buf are parameters
|
||||||
NewQueryLength:integer;
|
NewQueryLength:integer;
|
||||||
NewQuery:string;
|
NewQuery:string;
|
||||||
NewQueryIndex,BufIndex,CopyLen,i:integer; // Parambinding will have length ParamCount in the end
|
NewQueryIndex,BufIndex,CopyLen,i:integer; // Parambinding will have length ParamCount in the end
|
||||||
|
SimStrCount,b:integer; // in psSimulated mode this is the counter with the amount of repeating '$' signs
|
||||||
|
tmpParam:TParam;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if DoCreate then Clear;
|
if DoCreate then Clear;
|
||||||
// Parse the SQL and build ParamBinding
|
// Parse the SQL and build ParamBinding
|
||||||
ParamCount:=0;
|
ParamCount:=0;
|
||||||
|
SimStrCount := 1;
|
||||||
|
ReplaceString := '';
|
||||||
NewQueryLength:=Length(SQL);
|
NewQueryLength:=Length(SQL);
|
||||||
SetLength(ParamPart,ParamAllocStepSize);
|
SetLength(ParamPart,ParamAllocStepSize);
|
||||||
SetLength(Parambinding,ParamAllocStepSize);
|
SetLength(Parambinding,ParamAllocStepSize);
|
||||||
@ -286,9 +301,16 @@ begin
|
|||||||
SetLength(ParamBinding,NewLength);
|
SetLength(ParamBinding,NewLength);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// create Parameter and assign ParameterIndex
|
|
||||||
if DoCreate then
|
if DoCreate then
|
||||||
ParameterIndex := CreateParam(ftUnknown, ParamName, ptInput).Index
|
begin
|
||||||
|
// Check if this is the first occurance of the parameter
|
||||||
|
tmpParam := FindParam(ParamName);
|
||||||
|
// If so, create the parameter and assign the Parameterindex
|
||||||
|
if not assigned(tmpParam) then
|
||||||
|
ParameterIndex := CreateParam(ftUnknown, ParamName, ptInput).Index
|
||||||
|
else // else only assign the ParameterIndex
|
||||||
|
ParameterIndex := tmpParam.Index;
|
||||||
|
end
|
||||||
// else find ParameterIndex
|
// else find ParameterIndex
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -300,6 +322,13 @@ begin
|
|||||||
Inc(QuestionMarkParamCount);
|
Inc(QuestionMarkParamCount);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
if ParameterStyle in [psPostgreSQL,psSimulated] then
|
||||||
|
begin
|
||||||
|
if ParameterIndex > 8 then
|
||||||
|
inc(NewQueryLength,2)
|
||||||
|
else
|
||||||
|
inc(NewQueryLength,1)
|
||||||
|
end;
|
||||||
|
|
||||||
// store ParameterIndex in FParamIndex, ParamPart data
|
// store ParameterIndex in FParamIndex, ParamPart data
|
||||||
ParamBinding[ParamCount-1]:=ParameterIndex;
|
ParamBinding[ParamCount-1]:=ParameterIndex;
|
||||||
@ -310,6 +339,20 @@ begin
|
|||||||
Dec(NewQueryLength,p-ParamNameStart);
|
Dec(NewQueryLength,p-ParamNameStart);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
'$':
|
||||||
|
if ParameterStyle = psSimulated then
|
||||||
|
begin
|
||||||
|
b := 1;
|
||||||
|
while p^='$' do
|
||||||
|
begin
|
||||||
|
inc(p);
|
||||||
|
inc(b);
|
||||||
|
end;
|
||||||
|
if b > SimStrCount then SimStrCount := b;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Inc(p);
|
||||||
|
|
||||||
#0:Break;
|
#0:Break;
|
||||||
else
|
else
|
||||||
Inc(p);
|
Inc(p);
|
||||||
@ -321,12 +364,18 @@ begin
|
|||||||
|
|
||||||
if ParamCount>0 then
|
if ParamCount>0 then
|
||||||
begin
|
begin
|
||||||
// replace :ParamName by ? (using ParamPart array and NewQueryLength)
|
// replace :ParamName by ? for interbase and by $x for postgresql/psSimulated
|
||||||
if ParameterStyle = psPostgreSQL then
|
// (using ParamPart array and NewQueryLength)
|
||||||
if paramcount < 10 then
|
if (ParameterStyle = psSimulated) then
|
||||||
inc(NewQueryLength,paramcount)
|
begin
|
||||||
|
if (SimStrCount > 1) then
|
||||||
|
begin
|
||||||
|
inc(NewQueryLength,(paramcount)*(SimStrCount-1));
|
||||||
|
for b := 1 to SimStrCount do ReplaceString := ReplaceString+'$';
|
||||||
|
end
|
||||||
else
|
else
|
||||||
inc(NewQueryLength,(paramcount-9)*2+9);
|
ReplaceString := '$';
|
||||||
|
end;
|
||||||
|
|
||||||
SetLength(NewQuery,NewQueryLength);
|
SetLength(NewQuery,NewQueryLength);
|
||||||
NewQueryIndex:=1;
|
NewQueryIndex:=1;
|
||||||
@ -338,12 +387,16 @@ begin
|
|||||||
Inc(NewQueryIndex,CopyLen);
|
Inc(NewQueryIndex,CopyLen);
|
||||||
case ParameterStyle of
|
case ParameterStyle of
|
||||||
psInterbase : NewQuery[NewQueryIndex]:='?';
|
psInterbase : NewQuery[NewQueryIndex]:='?';
|
||||||
psPostgreSQL: begin
|
psPostgreSQL,
|
||||||
ParamName := IntToStr(i+1);
|
psSimulated : begin
|
||||||
NewQuery[NewQueryIndex]:='$';
|
ParamName := IntToStr(ParamBinding[i]+1);
|
||||||
Inc(NewQueryIndex);
|
for b := 1 to SimStrCount do
|
||||||
|
begin
|
||||||
|
NewQuery[NewQueryIndex]:='$';
|
||||||
|
Inc(NewQueryIndex);
|
||||||
|
end;
|
||||||
NewQuery[NewQueryIndex]:= paramname[1];
|
NewQuery[NewQueryIndex]:= paramname[1];
|
||||||
if i>10 then
|
if length(paramname)>1 then
|
||||||
begin
|
begin
|
||||||
Inc(NewQueryIndex);
|
Inc(NewQueryIndex);
|
||||||
NewQuery[NewQueryIndex]:= paramname[2]
|
NewQuery[NewQueryIndex]:= paramname[2]
|
||||||
@ -358,6 +411,7 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
NewQuery:=SQL;
|
NewQuery:=SQL;
|
||||||
|
|
||||||
Result := NewQuery;
|
Result := NewQuery;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ Type
|
|||||||
Row : MYSQL_ROW;
|
Row : MYSQL_ROW;
|
||||||
RowsAffected : QWord;
|
RowsAffected : QWord;
|
||||||
LastInsertID : QWord;
|
LastInsertID : QWord;
|
||||||
|
ParamBinding : TParamBinding;
|
||||||
|
ParamReplaceString : String;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TConnectionName = class (TSQLConnection)
|
TConnectionName = class (TSQLConnection)
|
||||||
@ -258,11 +260,13 @@ end;
|
|||||||
procedure TConnectionName.PrepareStatement(cursor: TSQLCursor;
|
procedure TConnectionName.PrepareStatement(cursor: TSQLCursor;
|
||||||
ATransaction: TSQLTransaction; buf: string;AParams : TParams);
|
ATransaction: TSQLTransaction; buf: string;AParams : TParams);
|
||||||
begin
|
begin
|
||||||
if assigned(AParams) and (AParams.count > 0) then
|
// if assigned(AParams) and (AParams.count > 0) then
|
||||||
DatabaseError('Parameters (not) yet supported for the MySQL SqlDB connection.',self);
|
// DatabaseError('Parameters (not) yet supported for the MySQL SqlDB connection.',self);
|
||||||
With Cursor as TCursorName do
|
With Cursor as TCursorName do
|
||||||
begin
|
begin
|
||||||
FStatement:=Buf;
|
FStatement:=Buf;
|
||||||
|
if assigned(AParams) and (AParams.count > 0) then
|
||||||
|
FStatement := AParams.ParseSQL(FStatement,false,psSimulated,paramBinding,ParamReplaceString);
|
||||||
if FStatementType=stSelect then
|
if FStatementType=stSelect then
|
||||||
FNeedData:=True;
|
FNeedData:=True;
|
||||||
ConnectMySQL(FQMySQL,FMySQL^.host,FMySQL^.user,FMySQL^.passwd);
|
ConnectMySQL(FQMySQL,FMySQL^.host,FMySQL^.user,FMySQL^.passwd);
|
||||||
@ -306,11 +310,15 @@ procedure TConnectionName.Execute(cursor: TSQLCursor;
|
|||||||
|
|
||||||
Var
|
Var
|
||||||
C : TCursorName;
|
C : TCursorName;
|
||||||
|
i : integer;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
C:=Cursor as TCursorName;
|
C:=Cursor as TCursorName;
|
||||||
If (C.FRes=Nil) then
|
If (C.FRes=Nil) then
|
||||||
begin
|
begin
|
||||||
|
if Assigned(AParams) and (AParams.count > 0) then
|
||||||
|
for i := 0 to AParams.count -1 do
|
||||||
|
C.FStatement := stringreplace(C.FStatement,C.ParamReplaceString+inttostr(AParams[i].Index+1),GetAsSQLText(AParams[i]),[rfReplaceAll,rfIgnoreCase]);
|
||||||
if mysql_query(c.FQMySQL,Pchar(C.FStatement))<>0 then
|
if mysql_query(c.FQMySQL,Pchar(C.FStatement))<>0 then
|
||||||
MySQLError(c.FQMYSQL,Format(SErrExecuting,[StrPas(mysql_error(c.FQMySQL))]),Self)
|
MySQLError(c.FQMYSQL,Format(SErrExecuting,[StrPas(mysql_error(c.FQMySQL))]),Self)
|
||||||
else
|
else
|
||||||
|
@ -76,7 +76,8 @@ type
|
|||||||
function StrToStatementType(s : string) : TStatementType; virtual;
|
function StrToStatementType(s : string) : TStatementType; virtual;
|
||||||
procedure DoInternalConnect; override;
|
procedure DoInternalConnect; override;
|
||||||
procedure DoInternalDisconnect; override;
|
procedure DoInternalDisconnect; override;
|
||||||
function GetAsSQLText(Field : TField) : string; virtual;
|
function GetAsSQLText(Field : TField) : string; overload; virtual;
|
||||||
|
function GetAsSQLText(Param : TParam) : string; overload; virtual;
|
||||||
function GetHandle : pointer; virtual; virtual;
|
function GetHandle : pointer; virtual; virtual;
|
||||||
|
|
||||||
Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
|
Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
|
||||||
@ -425,7 +426,7 @@ end;
|
|||||||
function TSQLConnection.GetAsSQLText(Field : TField) : string;
|
function TSQLConnection.GetAsSQLText(Field : TField) : string;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if not assigned(field) then Result := 'Null'
|
if (not assigned(field)) or field.IsNull then Result := 'Null'
|
||||||
else case field.DataType of
|
else case field.DataType of
|
||||||
ftString : Result := '''' + field.asstring + '''';
|
ftString : Result := '''' + field.asstring + '''';
|
||||||
ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime) + '''';
|
ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime) + '''';
|
||||||
@ -435,6 +436,20 @@ begin
|
|||||||
end; {case}
|
end; {case}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TSQLConnection.GetAsSQLText(Param: TParam) : string;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (not assigned(param)) or param.IsNull then Result := 'Null'
|
||||||
|
else case param.DataType of
|
||||||
|
ftString : Result := '''' + param.asstring + '''';
|
||||||
|
ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime) + '''';
|
||||||
|
ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Param.AsDateTime) + ''''
|
||||||
|
else
|
||||||
|
Result := Param.asstring;
|
||||||
|
end; {case}
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TSQLConnection.GetHandle: pointer;
|
function TSQLConnection.GetHandle: pointer;
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
|
Loading…
Reference in New Issue
Block a user