|
@@ -41,10 +41,12 @@ type
|
|
|
WhereStopPos : integer;
|
|
|
end;
|
|
|
|
|
|
+
|
|
|
type
|
|
|
TSQLConnection = class;
|
|
|
TSQLTransaction = class;
|
|
|
TCustomSQLQuery = class;
|
|
|
+ TCustomSQLStatement = Class;
|
|
|
TSQLQuery = class;
|
|
|
TSQLScript = class;
|
|
|
|
|
@@ -106,7 +108,7 @@ type
|
|
|
FHostName : string;
|
|
|
FCharSet : string;
|
|
|
FRole : String;
|
|
|
-
|
|
|
+ FStatements : TFPList;
|
|
|
function GetPort: cardinal;
|
|
|
function GetStatementInfo(const ASQL: string; Full: Boolean; ASchema : TSchemaType): TSQLStatementInfo;
|
|
|
procedure SetPort(const AValue: cardinal);
|
|
@@ -126,6 +128,8 @@ type
|
|
|
Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
|
|
|
Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
|
|
|
Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
|
|
|
+ Procedure RegisterStatement(S : TCustomSQLStatement);
|
|
|
+ Procedure UnRegisterStatement(S : TCustomSQLStatement);
|
|
|
|
|
|
procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
|
|
|
procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
|
|
@@ -145,6 +149,7 @@ type
|
|
|
function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
|
|
|
procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); virtual; abstract;
|
|
|
function RowsAffected(cursor: TSQLCursor): TRowsCount; virtual;
|
|
|
+ Property Statements : TFPList Read FStatements;
|
|
|
property Port: cardinal read GetPort write SetPort;
|
|
|
public
|
|
|
property Handle: Pointer read GetHandle;
|
|
@@ -224,17 +229,19 @@ type
|
|
|
FOrigSQL : String;
|
|
|
FServerSQL : String;
|
|
|
FTransaction: TSQLTransaction;
|
|
|
- FDatasource : TDatasource;
|
|
|
FParseSQL: Boolean;
|
|
|
+ FDataLink : TDataLink;
|
|
|
procedure SetDatabase(AValue: TSQLConnection);
|
|
|
procedure SetParams(AValue: TParams);
|
|
|
procedure SetSQL(AValue: TStrings);
|
|
|
procedure SetTransaction(AValue: TSQLTransaction);
|
|
|
Function GetPrepared : Boolean;
|
|
|
Protected
|
|
|
+ Function CreateDataLink : TDataLink; virtual;
|
|
|
procedure OnChangeSQL(Sender : TObject); virtual;
|
|
|
function GetDataSource: TDatasource; Virtual;
|
|
|
procedure SetDataSource(AValue: TDatasource); virtual;
|
|
|
+ Procedure CopyParamsFromMaster(CopyBound : Boolean); virtual;
|
|
|
procedure AllocateCursor;
|
|
|
procedure DeAllocateCursor;
|
|
|
Function GetSchemaType : TSchemaType; virtual;
|
|
@@ -285,7 +292,6 @@ type
|
|
|
private
|
|
|
// FCheckParams: Boolean;
|
|
|
// FCursor : TSQLCursor;
|
|
|
- FParams: TParams;
|
|
|
FSchemaType: TSchemaType;
|
|
|
// FSQL: TStringlist;
|
|
|
FUpdateable : boolean;
|
|
@@ -673,13 +679,18 @@ end;
|
|
|
|
|
|
procedure TCustomSQLStatement.SetDataSource(AValue: TDatasource);
|
|
|
|
|
|
+
|
|
|
+begin
|
|
|
+ if GetDatasource=AValue then Exit;
|
|
|
+ if (FDataLink=Nil) then
|
|
|
+ FDataLink:=CreateDataLink;
|
|
|
+ FDataLink.DataSource:=AValue;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCustomSQLStatement.CopyParamsFromMaster(CopyBound : Boolean);
|
|
|
begin
|
|
|
- if FDatasource=AValue then Exit;
|
|
|
- If Assigned(FDatasource) then
|
|
|
- FDatasource.RemoveFreeNotification(Self);
|
|
|
- FDatasource:=AValue;
|
|
|
- If Assigned(FDatasource) then
|
|
|
- FDatasource.FreeNotification(Self);
|
|
|
+ if Assigned(DataSource) and Assigned(DataSource.Dataset) then
|
|
|
+ FParams.CopyParamValuesFromDataset(DataSource.Dataset,CopyBound);
|
|
|
end;
|
|
|
|
|
|
procedure TCustomSQLStatement.SetParams(AValue: TParams);
|
|
@@ -711,8 +722,8 @@ end;
|
|
|
|
|
|
procedure TCustomSQLStatement.DoExecute;
|
|
|
begin
|
|
|
- If (FParams.Count>0) and Assigned(FDatasource) then
|
|
|
- ; // FMasterLink.CopyParamsFromMaster(False);
|
|
|
+ If (FParams.Count>0) and Assigned(Datasource) then
|
|
|
+ CopyParamsFromMaster(False);
|
|
|
If LogEvent(detExecute) then
|
|
|
Log(detExecute,FServerSQL);
|
|
|
Database.Execute(FCursor,Transaction, FParams);
|
|
@@ -723,6 +734,11 @@ begin
|
|
|
Result := Assigned(FCursor) and FCursor.FPrepared;
|
|
|
end;
|
|
|
|
|
|
+function TCustomSQLStatement.CreateDataLink: TDataLink;
|
|
|
+begin
|
|
|
+ Result:=TDataLink.Create;
|
|
|
+end;
|
|
|
+
|
|
|
function TCustomSQLStatement.CreateParams: TParams;
|
|
|
begin
|
|
|
Result:=TParams.Create(Nil);
|
|
@@ -756,7 +772,10 @@ begin
|
|
|
If (AComponent=FTransaction) then
|
|
|
FTransaction:=Nil
|
|
|
else if (AComponent=FDatabase) then
|
|
|
+ begin
|
|
|
+ UnPrepare;
|
|
|
FDatabase:=Nil;
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
constructor TCustomSQLStatement.Create(AOwner: TComponent);
|
|
@@ -774,6 +793,8 @@ begin
|
|
|
UnPrepare;
|
|
|
Transaction:=Nil;
|
|
|
Database:=Nil;
|
|
|
+ DataSource:=Nil;
|
|
|
+ FreeAndNil(FDataLink);
|
|
|
FreeAndNil(Fparams);
|
|
|
FreeAndNil(FSQL);
|
|
|
inherited Destroy;
|
|
@@ -812,13 +833,20 @@ procedure TCustomSQLStatement.AllocateCursor;
|
|
|
|
|
|
begin
|
|
|
if not assigned(FCursor) then
|
|
|
+ begin
|
|
|
+ // Do this as late as possible.
|
|
|
FCursor:=Database.AllocateCursorHandle;
|
|
|
+ FDatabase.RegisterStatement(Self);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
procedure TCustomSQLStatement.DeAllocateCursor;
|
|
|
begin
|
|
|
if Assigned(FCursor) and Assigned(Database) then
|
|
|
+ begin
|
|
|
DataBase.DeAllocateCursorHandle(FCursor);
|
|
|
+ Database.UnRegisterStatement(Self);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
procedure TCustomSQLStatement.DoPrepare;
|
|
@@ -860,8 +888,7 @@ begin
|
|
|
try
|
|
|
DoPrepare;
|
|
|
except
|
|
|
- if assigned(FCursor) then
|
|
|
- DataBase.DeAllocateCursorHandle(FCursor);
|
|
|
+ DeAllocateCursor;
|
|
|
Raise;
|
|
|
end;
|
|
|
end;
|
|
@@ -887,12 +914,18 @@ end;
|
|
|
|
|
|
function TCustomSQLStatement.GetDataSource: TDatasource;
|
|
|
begin
|
|
|
- Result:=FDatasource;
|
|
|
+ if Assigned(FDataLink) then
|
|
|
+ Result:=FDataLink.Datasource
|
|
|
+ else
|
|
|
+ Result:=Nil;
|
|
|
end;
|
|
|
|
|
|
procedure TCustomSQLStatement.Unprepare;
|
|
|
begin
|
|
|
- if Prepared then
|
|
|
+ // Some SQLConnections does not support statement [un]preparation, but they have allocated local cursor(s)
|
|
|
+ // so let them do cleanup f.e. cancel pending queries and/or free resultset
|
|
|
+ // and also do UnRegisterStatement!
|
|
|
+ if assigned(FCursor) then
|
|
|
DoUnprepare;
|
|
|
end;
|
|
|
|
|
@@ -950,11 +983,20 @@ begin
|
|
|
end;
|
|
|
|
|
|
procedure TSQLConnection.DoInternalDisconnect;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : integer;
|
|
|
+
|
|
|
begin
|
|
|
+ For I:=0 to FStatements.Count-1 do
|
|
|
+ TCustomSQLStatement(FStatements[i]).Unprepare;
|
|
|
+ FStatements.Clear;
|
|
|
end;
|
|
|
|
|
|
destructor TSQLConnection.Destroy;
|
|
|
begin
|
|
|
+ Connected:=False; // needed because we want to de-allocate statements
|
|
|
+ FreeAndNil(FStatements);
|
|
|
inherited Destroy;
|
|
|
end;
|
|
|
|
|
@@ -974,13 +1016,14 @@ begin
|
|
|
Transaction.EndTransaction;
|
|
|
end;
|
|
|
|
|
|
-Procedure TSQLConnection.ExecuteDirect(SQL: String);
|
|
|
+procedure TSQLConnection.ExecuteDirect(SQL: String);
|
|
|
|
|
|
begin
|
|
|
ExecuteDirect(SQL,FTransaction);
|
|
|
end;
|
|
|
|
|
|
-Procedure TSQLConnection.ExecuteDirect(SQL: String; ATransaction : TSQLTransaction);
|
|
|
+procedure TSQLConnection.ExecuteDirect(SQL: String;
|
|
|
+ ATransaction: TSQLTransaction);
|
|
|
|
|
|
var Cursor : TSQLCursor;
|
|
|
|
|
@@ -1059,6 +1102,7 @@ begin
|
|
|
inherited Create(AOwner);
|
|
|
FSQLFormatSettings:=DefaultSQLFormatSettings;
|
|
|
FFieldNameQuoteChars:=DoubleQuotes;
|
|
|
+ FStatements:=TFPList.Create;
|
|
|
end;
|
|
|
|
|
|
procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
|
|
@@ -1162,6 +1206,17 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
|
|
|
+begin
|
|
|
+ if FStatements.IndexOf(S)=-1 then
|
|
|
+ FStatements.Add(S);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
|
|
|
+begin
|
|
|
+ FStatements.Remove(S);
|
|
|
+end;
|
|
|
+
|
|
|
procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
|
|
|
begin
|
|
|
// empty
|
|
@@ -1573,18 +1628,13 @@ end;
|
|
|
|
|
|
procedure TCustomSQLQuery.InternalClose;
|
|
|
begin
|
|
|
- if not IsReadFromPacket then
|
|
|
+ if assigned(Cursor) then
|
|
|
begin
|
|
|
- if assigned(Cursor) and Cursor.FSelectable then
|
|
|
+ if Cursor.FSelectable then
|
|
|
FreeFldBuffers;
|
|
|
// Some SQLConnections does not support statement [un]preparation,
|
|
|
// so let them do cleanup f.e. cancel pending queries and/or free resultset
|
|
|
if not Prepared then FStatement.DoUnprepare;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- if assigned(Cursor) then
|
|
|
- FStatement.DeAllocateCursor;
|
|
|
end;
|
|
|
if DefaultFields then
|
|
|
DestroyFields;
|
|
@@ -1631,7 +1681,8 @@ begin
|
|
|
end;
|
|
|
*)
|
|
|
|
|
|
-Function TSQLConnection.GetStatementInfo(const ASQL : string; Full : Boolean; ASchema : TSchemaType) : TSQLStatementInfo;
|
|
|
+function TSQLConnection.GetStatementInfo(const ASQL: string; Full: Boolean;
|
|
|
+ ASchema: TSchemaType): TSQLStatementInfo;
|
|
|
|
|
|
|
|
|
type TParsePart = (ppStart,ppWith,ppSelect,ppTableName,ppFrom,ppWhere,ppGroup,ppOrder,ppBogus);
|
|
@@ -1810,24 +1861,22 @@ procedure TCustomSQLQuery.InternalOpen;
|
|
|
var tel, fieldc : integer;
|
|
|
f : TField;
|
|
|
IndexFields : TStrings;
|
|
|
- ReadFromFile: Boolean;
|
|
|
begin
|
|
|
- ReadFromFile:=IsReadFromPacket;
|
|
|
- if ReadFromFile then
|
|
|
+ if IsReadFromPacket then
|
|
|
begin
|
|
|
- FStatement.AllocateCursor;
|
|
|
- Cursor.FSelectable:=True;
|
|
|
- Cursor.FStatementType:=stSelect;
|
|
|
+ // When we read from file there is no need for Cursor, also note that Database may not be assigned
|
|
|
+ //FStatement.AllocateCursor;
|
|
|
+ //Cursor.FSelectable:=True;
|
|
|
+ //Cursor.FStatementType:=stSelect;
|
|
|
FUpdateable:=True;
|
|
|
+ BindFields(True);
|
|
|
end
|
|
|
else
|
|
|
+ begin
|
|
|
Prepare;
|
|
|
+ if not Cursor.FSelectable then
|
|
|
+ DatabaseError(SErrNoSelectStatement,Self);
|
|
|
|
|
|
- if not Cursor.FSelectable then
|
|
|
- DatabaseError(SErrNoSelectStatement,Self);
|
|
|
-
|
|
|
- if not ReadFromFile then
|
|
|
- begin
|
|
|
// Call UpdateServerIndexDefs before Execute, to avoid problems with connections
|
|
|
// which do not allow processing multiple recordsets at a time. (Microsoft
|
|
|
// calls this MARS, see bug 13241)
|
|
@@ -1869,9 +1918,7 @@ begin
|
|
|
end
|
|
|
else
|
|
|
BindFields(True);
|
|
|
- end
|
|
|
- else
|
|
|
- BindFields(True);
|
|
|
+ end;
|
|
|
|
|
|
if not ReadOnly and not FUpdateable and (FSchemaType=stNoSchema) then
|
|
|
begin
|
|
@@ -1903,39 +1950,20 @@ Type
|
|
|
|
|
|
TQuerySQLStatement = Class(TCustomSQLStatement)
|
|
|
protected
|
|
|
- FMasterLink: TMasterParamsDataLink;
|
|
|
FQuery : TCustomSQLQuery;
|
|
|
- function GetDataSource: TDatasource; override;
|
|
|
- procedure SetDataSource(AValue: TDatasource); override;
|
|
|
+ Function CreateDataLink : TDataLink; 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;
|
|
|
+function TQuerySQLStatement.CreateDataLink: TDataLink;
|
|
|
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);
|
|
|
+ Result:=TMasterParamsDataLink.Create(FQuery);
|
|
|
end;
|
|
|
|
|
|
function TQuerySQLStatement.GetSchemaType: TSchemaType;
|
|
@@ -1981,17 +2009,11 @@ procedure TQuerySQLStatement.OnChangeSQL(Sender: TObject);
|
|
|
begin
|
|
|
UnPrepare;
|
|
|
inherited OnChangeSQL(Sender);
|
|
|
- If CheckParams and Assigned(FMasterLink) then
|
|
|
- FMasterLink.RefreshParamNames;
|
|
|
+ If CheckParams and Assigned(FDataLink) then
|
|
|
+ (FDataLink as TMasterParamsDataLink).RefreshParamNames;
|
|
|
FQuery.ServerIndexDefs.Updated:=false;
|
|
|
end;
|
|
|
|
|
|
-destructor TQuerySQLStatement.Destroy;
|
|
|
-begin
|
|
|
- FreeAndNil(FMasterLink);
|
|
|
- inherited Destroy;
|
|
|
-end;
|
|
|
-
|
|
|
constructor TCustomSQLQuery.Create(AOwner : TComponent);
|
|
|
|
|
|
Var
|
|
@@ -1999,7 +2021,6 @@ Var
|
|
|
|
|
|
begin
|
|
|
inherited Create(AOwner);
|
|
|
- FParams := TParams.create(self);
|
|
|
F:=TQuerySQLStatement.Create(Self);
|
|
|
F.FQuery:=Self;
|
|
|
FStatement:=F;
|
|
@@ -2034,7 +2055,6 @@ begin
|
|
|
if Active then Close;
|
|
|
UnPrepare;
|
|
|
FreeAndNil(Fstatement);
|
|
|
- FreeAndNil(FParams);
|
|
|
// FreeAndNil(FSQL);
|
|
|
FreeAndNil(FInsertSQL);
|
|
|
FreeAndNil(FDeleteSQL);
|