* Refactor TSQLQuery to use TSQLStatement

git-svn-id: trunk@24742 -
This commit is contained in:
michael 2013-06-01 18:23:41 +00:00
parent 19d4b8dcd7
commit 03dd596485

View File

@ -221,20 +221,26 @@ type
FDatabase: TSQLConnection; FDatabase: TSQLConnection;
FParams: TParams; FParams: TParams;
FSQL: TStrings; FSQL: TStrings;
FSQLBuf : String; FOrigSQL : String;
FServerSQL : String;
FTransaction: TSQLTransaction; FTransaction: TSQLTransaction;
FDatasource : TDatasource; FDatasource : TDatasource;
FParseSQL: Boolean; FParseSQL: Boolean;
procedure OnChangeSQL(Sender : TObject);
procedure SetDatabase(AValue: TSQLConnection); procedure SetDatabase(AValue: TSQLConnection);
procedure SetDataSource(AValue: TDatasource);
procedure SetParams(AValue: TParams); procedure SetParams(AValue: TParams);
procedure SetSQL(AValue: TStrings); procedure SetSQL(AValue: TStrings);
procedure SetTransaction(AValue: TSQLTransaction); procedure SetTransaction(AValue: TSQLTransaction);
Function GetPrepared : Boolean; Function GetPrepared : Boolean;
Protected Protected
procedure OnChangeSQL(Sender : TObject); virtual;
function GetDataSource: TDatasource; Virtual;
procedure SetDataSource(AValue: TDatasource); virtual;
procedure AllocateCursor;
Function GetSchemaType : TSchemaType; virtual; Function GetSchemaType : TSchemaType; virtual;
Function GetSchemaObjectName : String; virtual;
Function GetSchemaPattern: String; virtual;
Function IsSelectable : Boolean ; virtual; Function IsSelectable : Boolean ; virtual;
procedure GetStatementInfo(Var ASQL: String; Full: Boolean; ASchema: TSchemaType; out Info: TSQLStatementInfo); virtual;
Procedure DoExecute; virtual; Procedure DoExecute; virtual;
procedure DoPrepare; virtual; procedure DoPrepare; virtual;
procedure DoUnPrepare; virtual; procedure DoUnPrepare; virtual;
@ -247,7 +253,7 @@ type
Property Transaction : TSQLTransaction Read FTransaction Write SetTransaction; Property Transaction : TSQLTransaction Read FTransaction Write SetTransaction;
Property SQL : TStrings Read FSQL Write SetSQL; Property SQL : TStrings Read FSQL Write SetSQL;
Property Params : TParams Read FParams Write SetParams; Property Params : TParams Read FParams Write SetParams;
Property Datasource : TDatasource Read FDataSource Write SetDataSource; Property Datasource : TDatasource Read GetDataSource Write SetDataSource;
Property ParseSQL : Boolean Read FParseSQL Write FParseSQL; Property ParseSQL : Boolean Read FParseSQL Write FParseSQL;
Property CheckParams : Boolean Read FCheckParams Write FCheckParams default true; Property CheckParams : Boolean Read FCheckParams Write FCheckParams default true;
Public Public
@ -276,24 +282,26 @@ type
TCustomSQLQuery = class (TCustomBufDataset) TCustomSQLQuery = class (TCustomBufDataset)
private private
FCheckParams: Boolean; // FCheckParams: Boolean;
FCursor : TSQLCursor; // FCursor : TSQLCursor;
FParams: TParams;
FSchemaType: TSchemaType;
// FSQL: TStringlist;
FUpdateable : boolean; FUpdateable : boolean;
FTableName : string; FTableName : string;
FSQL : TStringList; FStatement : TCustomSQLStatement;
FUpdateSQL, FUpdateSQL,
FInsertSQL, FInsertSQL,
FDeleteSQL : TStringList; FDeleteSQL : TStringList;
FIsEOF : boolean; FIsEOF : boolean;
FLoadingFieldDefs : boolean; FLoadingFieldDefs : boolean;
FUpdateMode : TUpdateMode; FUpdateMode : TUpdateMode;
FParams : TParams;
FusePrimaryKeyAsKey : Boolean; FusePrimaryKeyAsKey : Boolean;
FSQLBuf : String; FSQLBuf : String;
FWhereStartPos : integer; FWhereStartPos : integer;
FWhereStopPos : integer; FWhereStopPos : integer;
FParseSQL : boolean; // FParseSQL : boolean;
FMasterLink : TMasterParamsDatalink; // FMasterLink : TMasterParamsDatalink;
// FSchemaInfo : TSchemaInfo; // FSchemaInfo : TSchemaInfo;
FServerFilterText : string; FServerFilterText : string;
@ -302,7 +310,6 @@ type
FServerIndexDefs : TServerIndexDefs; FServerIndexDefs : TServerIndexDefs;
// Used by SetSchemaType // Used by SetSchemaType
FSchemaType : TSchemaType;
FSchemaObjectName : string; FSchemaObjectName : string;
FSchemaPattern : string; FSchemaPattern : string;
@ -310,24 +317,31 @@ type
FDeleteQry, FDeleteQry,
FInsertQry : TCustomSQLQuery; FInsertQry : TCustomSQLQuery;
procedure FreeFldBuffers; procedure FreeFldBuffers;
function GetCheckParams: Boolean;
function GetParams: TParams;
function GetParseSQL: Boolean;
function GetServerIndexDefs: TServerIndexDefs; function GetServerIndexDefs: TServerIndexDefs;
function GetSQL: TStringlist;
function GetStatementType : TStatementType; function GetStatementType : TStatementType;
procedure SetCheckParams(AValue: Boolean);
procedure SetDeleteSQL(const AValue: TStringlist); procedure SetDeleteSQL(const AValue: TStringlist);
procedure SetInsertSQL(const AValue: TStringlist); procedure SetInsertSQL(const AValue: TStringlist);
procedure SetParams(AValue: TParams);
procedure SetParseSQL(AValue : Boolean); procedure SetParseSQL(AValue : Boolean);
procedure SetSQL(const AValue: TStringlist); procedure SetSQL(const AValue: TStringlist);
procedure SetUpdateSQL(const AValue: TStringlist); procedure SetUpdateSQL(const AValue: TStringlist);
procedure SetUsePrimaryKeyAsKey(AValue : Boolean); procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
procedure SetUpdateMode(AValue : TUpdateMode); procedure SetUpdateMode(AValue : TUpdateMode);
procedure OnChangeSQL(Sender : TObject); // procedure OnChangeSQL(Sender : TObject);
procedure OnChangeModifySQL(Sender : TObject); procedure OnChangeModifySQL(Sender : TObject);
procedure Execute; procedure Execute;
Function SQLParser(const ASQL : string) : TStatementType; // Function SQLParser(const ASQL : string) : TStatementType;
procedure ApplyFilter; procedure ApplyFilter;
Function AddFilter(SQLstr : string) : string; Function AddFilter(SQLstr : string) : string;
protected protected
// abstract & virtual methods of TBufDataset // abstract & virtual methods of TBufDataset
function Fetch : boolean; override; function Fetch : boolean; override;
Function Cursor : TSQLCursor;
function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override; function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
// abstract & virtual methods of TDataset // abstract & virtual methods of TDataset
procedure UpdateServerIndexDefs; virtual; procedure UpdateServerIndexDefs; virtual;
@ -395,16 +409,16 @@ type
// protected // protected
property SchemaType : TSchemaType read FSchemaType default stNoSchema; property SchemaType : TSchemaType read FSchemaType default stNoSchema;
property Transaction; property Transaction;
property SQL : TStringlist read FSQL write SetSQL; property SQL : TStringlist read GetSQL write SetSQL;
property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL; property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL;
property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL; property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL;
property DeleteSQL : TStringlist read FDeleteSQL write SetDeleteSQL; property DeleteSQL : TStringlist read FDeleteSQL write SetDeleteSQL;
property Params : TParams read FParams write FParams; property Params : TParams read GetParams Write SetParams;
property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly; property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode default upWhereKeyOnly;
property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true; property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey default true;
property StatementType : TStatementType read GetStatementType; property StatementType : TStatementType read GetStatementType;
property ParseSQL : Boolean read FParseSQL write SetParseSQL default true; property ParseSQL : Boolean read GetParseSQL write SetParseSQL default true;
Property CheckParams : Boolean Read FCheckParams Write FCheckParams default true; Property CheckParams : Boolean Read GetCheckParams Write SetCheckParams default true;
Property DataSource : TDatasource Read GetDataSource Write SetDatasource; Property DataSource : TDatasource Read GetDataSource Write SetDatasource;
property ServerFilter: string read FServerFilterText write SetServerFilterText; property ServerFilter: string read FServerFilterText write SetServerFilterText;
property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False; property ServerFiltered: Boolean read FServerFiltered write SetServerFiltered default False;
@ -699,7 +713,7 @@ begin
If (FParams.Count>0) and Assigned(FDatasource) then If (FParams.Count>0) and Assigned(FDatasource) then
; // FMasterLink.CopyParamsFromMaster(False); ; // FMasterLink.CopyParamsFromMaster(False);
If LogEvent(detExecute) then If LogEvent(detExecute) then
Log(detExecute,FSQLBuf); Log(detExecute,FServerSQL);
Database.Execute(FCursor,Transaction, FParams); Database.Execute(FCursor,Transaction, FParams);
end; end;
@ -770,29 +784,58 @@ begin
Result:=stNoSchema Result:=stNoSchema
end; end;
function TCustomSQLStatement.GetSchemaObjectName: String;
begin
Result:='';
end;
function TCustomSQLStatement.GetSchemaPattern: String;
begin
Result:='';
end;
function TCustomSQLStatement.IsSelectable: Boolean; function TCustomSQLStatement.IsSelectable: Boolean;
begin begin
Result:=False; Result:=False;
end; end;
procedure TCustomSQLStatement.GetStatementInfo(var ASQL: String; Full: Boolean;
ASchema: TSchemaType; out Info: TSQLStatementInfo);
begin
Info:=Database.GetStatementInfo(ASQL,Full,ASchema);
end;
procedure TCustomSQLStatement.AllocateCursor;
begin
if not assigned(FCursor) then
FCursor:=Database.AllocateCursorHandle;
end;
procedure TCustomSQLStatement.DoPrepare; procedure TCustomSQLStatement.DoPrepare;
var var
StmType: TStatementType; StmType: TStatementType;
I : TSQLStatementInfo;
begin begin
FSQLBuf := TrimRight(FSQL.Text); if GetSchemaType=stNoSchema then
if (FSQLBuf='') then FOrigSQL := TrimRight(FSQL.Text)
else
FOrigSQL := Database.GetSchemaInfoSQL(GetSchemaType, GetSchemaObjectName, GetSchemaPattern);
if (FOrigSQL='') then
DatabaseError(SErrNoStatement); DatabaseError(SErrNoStatement);
StmType:=Database.GetStatementInfo(FSQLBuf,ParseSQL,GetSchemaType).StatementType; FServerSQL:=FOrigSQL;
if not assigned(FCursor) then GetStatementInfo(FServerSQL,ParseSQL,GetSchemaType,I);
FCursor:=Database.AllocateCursorHandle; StmType:=I.StatementType;
AllocateCursor;
FCursor.FSelectable:=False; FCursor.FSelectable:=False;
FCursor.FStatementType:=StmType; FCursor.FStatementType:=StmType;
FCursor.FSchemaType:=GetSchemaType; FCursor.FSchemaType:=GetSchemaType;
If LogEvent(detPrepare) then If LogEvent(detPrepare) then
Log(detPrepare,FSQLBuf); Log(detPrepare,FServerSQL);
Database.PrepareStatement(FCursor,Transaction,FSQLBuf,FParams); Database.PrepareStatement(FCursor,Transaction,FServerSQL,FParams);
end; end;
procedure TCustomSQLStatement.Prepare; procedure TCustomSQLStatement.Prepare;
@ -834,6 +877,11 @@ begin
FreeAndNil(FCursor); FreeAndNil(FCursor);
end; end;
function TCustomSQLStatement.GetDataSource: TDatasource;
begin
Result:=FDatasource;
end;
procedure TCustomSQLStatement.Unprepare; procedure TCustomSQLStatement.Unprepare;
begin begin
if Prepared then if Prepared then
@ -1283,13 +1331,13 @@ begin
end; end;
{ TCustomSQLQuery } { TCustomSQLQuery }
(*
procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject); procedure TCustomSQLQuery.OnChangeSQL(Sender : TObject);
var ConnOptions : TConnOptions; var ConnOptions : TConnOptions;
NewParams: TParams; NewParams: TParams;
begin begin
UnPrepare;
FSchemaType:=stNoSchema; FSchemaType:=stNoSchema;
if (FSQL <> nil) and CheckParams then if (FSQL <> nil) and CheckParams then
begin begin
@ -1306,10 +1354,9 @@ begin
finally finally
NewParams.Free; NewParams.Free;
end; end;
If Assigned(FMasterLink) then
FMasterLink.RefreshParamNames;
end; end;
end; end;
*)
function TCustomSQLQuery.ParamByName(const AParamName: String): TParam; function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
@ -1328,6 +1375,8 @@ procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
begin begin
UnPrepare; UnPrepare;
inherited; inherited;
If Assigned(FStatement) then
FStatement.Transaction:=TSQLTransaction(Value);
If (Transaction<>Nil) and (Database=Nil) then If (Transaction<>Nil) and (Database=Nil) then
Database:=TSQLTransaction(Transaction).Database; Database:=TSQLTransaction(Transaction).Database;
end; end;
@ -1342,19 +1391,27 @@ begin
if assigned(value) and not (Value is TSQLConnection) then if assigned(value) and not (Value is TSQLConnection) then
DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self); DatabaseErrorFmt(SErrNotASQLConnection,[value.Name],self);
UnPrepare; UnPrepare;
if assigned(FCursor) then TSQLConnection(DataBase).DeAllocateCursorHandle(FCursor);
db := TSQLConnection(Value); db := TSQLConnection(Value);
If Assigned(FStatement) then
FStatement.Database:=DB;
inherited setdatabase(value); inherited setdatabase(value);
(*
FStatement.Database:=Db,
if assigned(FCursor) then TSQLConnection(DataBase).DeAllocateCursorHandle(FCursor);
*)
if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
transaction := Db.Transaction; transaction := Db.Transaction;
OnChangeSQL(Self); // FStatement.OnChangeSQL(Self);
end; end;
end; end;
function TCustomSQLQuery.IsPrepared: Boolean; function TCustomSQLQuery.IsPrepared: Boolean;
begin begin
Result := Assigned(FCursor) and FCursor.FPrepared; if Assigned(Fstatement) then
Result := FStatement.Prepared
else
Result:=False;
end; end;
function TCustomSQLQuery.AddFilter(SQLstr: string): string; function TCustomSQLQuery.AddFilter(SQLstr: string): string;
@ -1381,17 +1438,11 @@ var S : String;
begin begin
FreeFldBuffers; FreeFldBuffers;
TSQLConnection(Database).UnPrepareStatement(FCursor); FStatement.Unprepare;
FIsEOF := False; FIsEOF := False;
inherited internalclose; inherited internalclose;
FStatement.DoPrepare;
s := FSQLBuf; FStatement.DoExecute;
if ServerFiltered then s := AddFilter(s);
TSQLConnection(Database).PrepareStatement(FCursor,(Transaction as TSQLTransaction),S,FParams);
Execute;
inherited InternalOpen; inherited InternalOpen;
First; First;
end; end;
@ -1409,11 +1460,13 @@ end;
procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean); procedure TCustomSQLQuery.SetServerFiltered(Value: Boolean);
begin begin
if Value and not FParseSQL then DatabaseErrorFmt(SNoParseSQL,['Filtering ']); if Value and not ParseSQL then
DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
if (ServerFiltered <> Value) then if (ServerFiltered <> Value) then
begin begin
FServerFiltered := Value; FServerFiltered := Value;
if active then ApplyFilter; if active then
ApplyFilter;
end; end;
end; end;
@ -1427,72 +1480,41 @@ begin
end; end;
procedure TCustomSQLQuery.Prepare; procedure TCustomSQLQuery.Prepare;
var
db : tsqlconnection;
sqltr : tsqltransaction;
StmType: TStatementType;
begin begin
if not IsPrepared then FStatement.Prepare;
begin If Assigned(Fstatement.FCursor) then
db := TSQLConnection(Database); With FStatement.FCursor do
sqltr := (transaction as tsqltransaction); FInitFieldDef:=FSelectable;
if not assigned(Db) then
DatabaseError(SErrDatabasenAssigned);
if not assigned(sqltr) then
DatabaseError(SErrTransactionnSet);
if not Db.Connected then db.Open;
if not sqltr.Active then sqltr.StartTransaction;
if FSchemaType=stNoSchema then
FSQLBuf := TrimRight(FSQL.Text)
else
FSQLBuf := db.GetSchemaInfoSQL(FSchemaType, FSchemaObjectName, FSchemaPattern);
if FSQLBuf = '' then
DatabaseError(SErrNoStatement);
StmType:=SQLParser(FSQLBuf);
// There may no error occur between the allocation of the cursor and
// the preparation of the cursor. Because internalclose (which is called in
// case of an exception) assumes that allocated cursors are also prepared,
// and thus calls unprepare.
// A call to unprepare while the cursor is not prepared at all can lead to
// unpredictable results.
if not assigned(FCursor) then
FCursor := Db.AllocateCursorHandle;
FCursor.FSelectable:=True; // let PrepareStatement and/or Execute alter it
FCursor.FStatementType:=StmType;
FCursor.FSchemaType := FSchemaType;
if ServerFiltered then
begin
If LogEvent(detPrepare) then
Log(detPrepare,AddFilter(FSQLBuf));
Db.PrepareStatement(FCursor,sqltr,AddFilter(FSQLBuf),FParams)
end
else
begin
If LogEvent(detPrepare) then
Log(detPrepare,FSQLBuf);
Db.PrepareStatement(FCursor,sqltr,FSQLBuf,FParams);
end;
FCursor.FInitFieldDef := FCursor.FSelectable;
end;
end; end;
procedure TCustomSQLQuery.UnPrepare; procedure TCustomSQLQuery.UnPrepare;
begin begin
CheckInactive; CheckInactive;
if IsPrepared then with TSQLConnection(DataBase) do If Assigned(FStatement) then
UnPrepareStatement(FCursor); FStatement.Unprepare;
end; end;
procedure TCustomSQLQuery.FreeFldBuffers; procedure TCustomSQLQuery.FreeFldBuffers;
begin begin
if assigned(FCursor) then TSQLConnection(Database).FreeFldBuffers(FCursor); if assigned(Cursor) then
TSQLConnection(Database).FreeFldBuffers(Cursor);
end;
function TCustomSQLQuery.GetCheckParams: Boolean;
begin
Result:=FStatement.CheckParams;
end;
function TCustomSQLQuery.GetParams: TParams;
begin
Result:=FStatement.Params;
end;
function TCustomSQLQuery.GetParseSQL: Boolean;
begin
Result:=FStatement.ParseSQL;
end; end;
function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs; function TCustomSQLQuery.GetServerIndexDefs: TServerIndexDefs;
@ -1500,36 +1522,40 @@ begin
Result := FServerIndexDefs; Result := FServerIndexDefs;
end; end;
function TCustomSQLQuery.GetSQL: TStringlist;
begin
Result:=TStringList(Fstatement.SQL);
end;
function TCustomSQLQuery.Fetch : boolean; function TCustomSQLQuery.Fetch : boolean;
begin begin
if not FCursor.FSelectable then if Not Assigned(Cursor) then
Exit; Exit;
if not Cursor.FSelectable then
if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(FCursor); Exit;
if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(Cursor);
Result := not FIsEOF; Result := not FIsEOF;
end; end;
function TCustomSQLQuery.Cursor: TSQLCursor;
begin
Result:=FStatement.Cursor;
end;
procedure TCustomSQLQuery.Execute; procedure TCustomSQLQuery.Execute;
begin begin
If (FParams.Count>0) and Assigned(FMasterLink) then FStatement.Execute;
FMasterLink.CopyParamsFromMaster(False);
If LogEvent(detExecute) then
Log(detExecute,FSQLBuf);
TSQLConnection(Database).Execute(FCursor,Transaction as TSQLTransaction, FParams);
end; end;
function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; function TCustomSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
begin begin
result := TSQLConnection(Database).LoadField(FCursor,FieldDef,buffer, Createblob) result := TSQLConnection(Database).LoadField(Cursor,FieldDef,buffer, Createblob)
end; end;
function TCustomSQLQuery.RowsAffected: TRowsCount; function TCustomSQLQuery.RowsAffected: TRowsCount;
begin begin
Result := -1; Result:=Fstatement.RowsAffected;
if not Assigned(Database) then Exit;
//assert(Database is TSQLConnection);
Result := TSQLConnection(Database).RowsAffected(FCursor);
end; end;
procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean); procedure TCustomSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
@ -1541,9 +1567,8 @@ procedure TCustomSQLQuery.InternalClose;
begin begin
if not IsReadFromPacket then if not IsReadFromPacket then
begin begin
if assigned(FCursor) and FCursor.FSelectable then FreeFldBuffers; if assigned(Cursor) and Cursor.FSelectable then FreeFldBuffers;
// Database and FCursor could be nil, for example if the database is not assigned, and .open is called FStatement.Unprepare;
if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(FCursor);
end; end;
if DefaultFields then if DefaultFields then
DestroyFields; DestroyFields;
@ -1565,28 +1590,30 @@ begin
try try
FieldDefs.Clear; FieldDefs.Clear;
if not Assigned(Database) then DatabaseError(SErrDatabasenAssigned); if not Assigned(Database) then DatabaseError(SErrDatabasenAssigned);
TSQLConnection(Database).AddFieldDefs(FCursor,FieldDefs); TSQLConnection(Database).AddFieldDefs(Cursor,FieldDefs);
finally finally
FLoadingFieldDefs := False; FLoadingFieldDefs := False;
if Assigned(FCursor) then FCursor.FInitFieldDef := false; if Assigned(Cursor) then Cursor.FInitFieldDef := false;
end; end;
end; end;
(*
function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType; function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
Var Var
I : TSQLStatementInfo; I : TSQLStatementInfo;
begin begin
I:=(Database as TSQLConnection).GetStatementInfo(ASQL,ParseSQL,FSchemaType); I:=(Database as TSQLConnection).GetStatementInfo(ASQL,ParseSQL,SchemaType);
FTableName:=I.TableName; FTableName:=I.TableName;
FUpdateable:=I.Updateable; FUpdateable:=I.Updateable;
FWhereStartPos:=I.WhereStartPos; FWhereStartPos:=I.WhereStartPos;
FWhereStopPos:=I.WhereStopPos; FWhereStopPos:=I.WhereStopPos;
Result:=I.StatementType; Result:=I.StatementType;
end; end;
*)
Function TSQLConnection.GetStatementInfo(const ASQL : string; Full : Boolean; ASchema : TSchemaType) : TSQLStatementInfo; Function TSQLConnection.GetStatementInfo(const ASQL : string; Full : Boolean; ASchema : TSchemaType) : TSQLStatementInfo;
@ -1772,16 +1799,15 @@ begin
ReadFromFile:=IsReadFromPacket; ReadFromFile:=IsReadFromPacket;
if ReadFromFile then if ReadFromFile then
begin begin
if not assigned(FCursor) then FStatement.AllocateCursor;
FCursor := TSQLConnection(Database).AllocateCursorHandle; Cursor.FSelectable:=True;
FCursor.FSelectable:=True; Cursor.FStatementType:=stSelect;
FCursor.FStatementType:=stSelect;
FUpdateable:=True; FUpdateable:=True;
end end
else else
Prepare; Prepare;
if not FCursor.FSelectable then if not Cursor.FSelectable then
DatabaseError(SErrNoSelectStatement,Self); DatabaseError(SErrNoSelectStatement,Self);
if not ReadFromFile then if not ReadFromFile then
@ -1793,12 +1819,12 @@ begin
UpdateServerIndexDefs; UpdateServerIndexDefs;
Execute; Execute;
if not FCursor.FSelectable then if not Cursor.FSelectable then
DatabaseError(SErrNoSelectStatement,Self); DatabaseError(SErrNoSelectStatement,Self);
// InternalInitFieldDef is only called after a prepare. i.e. not twice if // InternalInitFieldDef is only called after a prepare. i.e. not twice if
// a dataset is opened - closed - opened. // a dataset is opened - closed - opened.
if FCursor.FInitFieldDef then InternalInitFieldDefs; if Cursor.FInitFieldDef then InternalInitFieldDefs;
if DefaultFields then if DefaultFields then
begin begin
CreateFields; CreateFields;
@ -1848,18 +1874,120 @@ begin
Prepare; Prepare;
Execute; Execute;
finally finally
// FCursor has to be assigned, or else the prepare went wrong before PrepareStatment was // Cursor has to be assigned, or else the prepare went wrong before PrepareStatment was
// called, so UnPrepareStatement shoudn't be called either // called, so UnPrepareStatement shoudn't be called either
if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then TSQLConnection(database).UnPrepareStatement(FCursor); if (not IsPrepared) and (assigned(database)) and (assigned(Cursor)) then TSQLConnection(database).UnPrepareStatement(Cursor);
end; end;
end; end;
Type
{ TQuerySQLStatement }
TQuerySQLStatement = Class(TCustomSQLStatement)
protected
FMasterLink: TMasterParamsDataLink;
FQuery : TCustomSQLQuery;
function GetDataSource: TDatasource; override;
procedure SetDataSource(AValue: TDatasource); override;
Function GetSchemaType : TSchemaType; override;
Function GetSchemaObjectName : String; override;
Function GetSchemaPattern: String; override;
procedure GetStatementInfo(Var ASQL: String; Full: Boolean; ASchema: TSchemaType; out Info: TSQLStatementInfo); override;
procedure OnChangeSQL(Sender : TObject); override;
Public
destructor Destroy; override;
end;
{ TQuerySQLStatement }
function TQuerySQLStatement.GetDataSource: TDatasource;
begin
Result:=inherited GetDataSource;
end;
procedure TQuerySQLStatement.SetDataSource(AValue: TDatasource);
begin
inherited SetDataSource(AValue);
If Assigned(AValue) then
begin
AValue.FreeNotification(Self);
If (FMasterLink=Nil) then
FMasterLink:=TMasterParamsDataLink.Create(FQuery);
FMasterLink.Datasource:=AValue;
end
else
FreeAndNil(FMasterLink);
end;
function TQuerySQLStatement.GetSchemaType: TSchemaType;
begin
if Assigned(FQuery) then
Result:=FQuery.FSchemaType
else
Result:=stNoSchema;
end;
function TQuerySQLStatement.GetSchemaObjectName: String;
begin
if Assigned(FQuery) then
Result:=FQuery.FSchemaObjectname
else
Result:=inherited GetSchemaObjectName;
end;
function TQuerySQLStatement.GetSchemaPattern: String;
begin
if Assigned(FQuery) then
Result:=FQuery.FSchemaPattern
else
Result:=inherited GetSchemaPattern;
end;
procedure TQuerySQLStatement.GetStatementInfo(var ASQL: String; Full: Boolean;
ASchema: TSchemaType; out Info: TSQLStatementInfo);
begin
inherited GetStatementInfo(ASQL, Full, ASchema, Info);
If Assigned(FQuery) then
begin
FQuery.FWhereStartPos:=Info.WhereStartPos;
FQuery.FWhereStopPos:=Info.WhereStopPos;
FQuery.FUpdateable:=info.Updateable;
FQuery.FTableName:=Info.TableName;
if FQuery.ServerFiltered then
ASQL:=FQuery.AddFilter(ASQL);
end;
end;
procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
begin
UnPrepare;
inherited OnChangeSQL(Sender);
If CheckParams and Assigned(FMasterLink) then
FMasterLink.RefreshParamNames;
end;
destructor TQuerySQLStatement.Destroy;
begin
FreeAndNil(FMasterLink);
inherited Destroy;
end;
constructor TCustomSQLQuery.Create(AOwner : TComponent); constructor TCustomSQLQuery.Create(AOwner : TComponent);
Var
F : TQuerySQLStatement;
begin begin
inherited Create(AOwner); inherited Create(AOwner);
FParams := TParams.create(self); FParams := TParams.create(self);
FSQL := TStringList.Create; F:=TQuerySQLStatement.Create(Self);
FSQL.OnChange := @OnChangeSQL; F.FQuery:=Self;
FStatement:=F;
//FSQL := TStringList.Create;
// FSQL.OnChange := @OnChangeSQL;
FUpdateSQL := TStringList.Create; FUpdateSQL := TStringList.Create;
FUpdateSQL.OnChange := @OnChangeModifySQL; FUpdateSQL.OnChange := @OnChangeModifySQL;
@ -1870,8 +1998,6 @@ begin
FServerIndexDefs := TServerIndexDefs.Create(Self); FServerIndexDefs := TServerIndexDefs.Create(Self);
FParseSQL := True;
CheckParams:=True;
FServerFiltered := False; FServerFiltered := False;
FServerFilterText := ''; FServerFilterText := '';
@ -1889,10 +2015,9 @@ destructor TCustomSQLQuery.Destroy;
begin begin
if Active then Close; if Active then Close;
UnPrepare; UnPrepare;
if assigned(FCursor) then TSQLConnection(Database).DeAllocateCursorHandle(FCursor); FreeAndNil(Fstatement);
FreeAndNil(FMasterLink);
FreeAndNil(FParams); FreeAndNil(FParams);
FreeAndNil(FSQL); // FreeAndNil(FSQL);
FreeAndNil(FInsertSQL); FreeAndNil(FInsertSQL);
FreeAndNil(FDeleteSQL); FreeAndNil(FDeleteSQL);
FreeAndNil(FUpdateSQL); FreeAndNil(FUpdateSQL);
@ -1911,18 +2036,14 @@ procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
begin begin
CheckInactive; CheckInactive;
FStatement.ParseSQL:=AValue;
if not AValue then if not AValue then
begin
FServerFiltered := False; FServerFiltered := False;
FParseSQL := False;
end
else
FParseSQL := True;
end; end;
procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist); procedure TCustomSQLQuery.SetSQL(const AValue: TStringlist);
begin begin
FSQL.Assign(AValue); FStatement.SQL.Assign(AValue);
end; end;
procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist); procedure TCustomSQLQuery.SetUpdateSQL(const AValue: TStringlist);
@ -2092,8 +2213,8 @@ end;
function TCustomSQLQuery.GetCanModify: Boolean; function TCustomSQLQuery.GetCanModify: Boolean;
begin begin
// the test for assigned(FCursor) is needed for the case that the dataset isn't opened // the test for assigned(Cursor) is needed for the case that the dataset isn't opened
if assigned(FCursor) and (FCursor.FStatementType = stSelect) then if assigned(Cursor) and (Cursor.FStatementType = stSelect) then
Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional) Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
else else
Result := False; Result := False;
@ -2116,7 +2237,7 @@ end;
procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef; procedure TCustomSQLQuery.LoadBlobIntoBuffer(FieldDef: TFieldDef;
ABlobBuf: PBufBlobField); ABlobBuf: PBufBlobField);
begin begin
TSQLConnection(DataBase).LoadBlobIntoBuffer(FieldDef, ABlobBuf, FCursor,(Transaction as TSQLTransaction)); TSQLConnection(DataBase).LoadBlobIntoBuffer(FieldDef, ABlobBuf, Cursor,(Transaction as TSQLTransaction));
end; end;
procedure TCustomSQLQuery.BeforeRefreshOpenCursor; procedure TCustomSQLQuery.BeforeRefreshOpenCursor;
@ -2126,7 +2247,7 @@ begin
// problems because in SetActive(false) queries are always // problems because in SetActive(false) queries are always
// unprepared. (which is also wrong, but has to be fixed later) // unprepared. (which is also wrong, but has to be fixed later)
if IsPrepared then with TSQLConnection(DataBase) do if IsPrepared then with TSQLConnection(DataBase) do
UnPrepareStatement(FCursor); UnPrepareStatement(Cursor);
end; end;
function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean; function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
@ -2152,10 +2273,15 @@ end;
function TCustomSQLQuery.GetStatementType : TStatementType; function TCustomSQLQuery.GetStatementType : TStatementType;
begin begin
if assigned(FCursor) then if Assigned(Cursor) then
Result := FCursor.FStatementType Result:=Cursor.FStatementType
else else
Result := stUnknown; Result:=stUnknown;
end;
procedure TCustomSQLQuery.SetCheckParams(AValue: Boolean);
begin
FStatement.CheckParams:=Avalue;
end; end;
procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist); procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
@ -2168,6 +2294,11 @@ begin
FInsertSQL.Assign(AValue); FInsertSQL.Assign(AValue);
end; end;
procedure TCustomSQLQuery.SetParams(AValue: TParams);
begin
FStatement.Params.Assign(AValue);
end;
procedure TCustomSQLQuery.SetDataSource(AValue: TDatasource); procedure TCustomSQLQuery.SetDataSource(AValue: TDatasource);
Var Var
@ -2181,23 +2312,15 @@ begin
DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self); DatabaseError(SErrCircularDataSourceReferenceNotAllowed,Self);
If Assigned(DS) then If Assigned(DS) then
DS.RemoveFreeNotification(Self); DS.RemoveFreeNotification(Self);
If Assigned(AValue) then FStatement.Datasource:=AValue;
begin
AValue.FreeNotification(Self);
If (FMasterLink=Nil) then
FMasterLink:=TMasterParamsDataLink.Create(Self);
FMasterLink.Datasource:=AValue;
end
else
FreeAndNil(FMasterLink);
end; end;
end; end;
function TCustomSQLQuery.GetDataSource: TDatasource; function TCustomSQLQuery.GetDataSource: TDatasource;
begin begin
If Assigned(FMasterLink) then If Assigned(FStatement) then
Result:=FMasterLink.DataSource Result:=FStatement.Datasource
else else
Result:=Nil; Result:=Nil;
end; end;