
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5438 8e941d3f-bd1b-0410-a28a-d453659cc2b4
6752 lines
238 KiB
ObjectPascal
6752 lines
238 KiB
ObjectPascal
{*********************************************************}
|
|
{* FlashFiler: Remote Server Engine Classes *}
|
|
{*********************************************************}
|
|
|
|
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TurboPower FlashFiler
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* TurboPower Software
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
{$I ffdefine.inc}
|
|
|
|
unit ffclreng;
|
|
|
|
interface
|
|
uses
|
|
Windows,
|
|
dialogs,
|
|
Classes,
|
|
SysUtils,
|
|
ffllbase,
|
|
fflldict,
|
|
ffdtmsgq,
|
|
ffllcomm,
|
|
ffllcomp,
|
|
fflleng,
|
|
ffllexcp,
|
|
ffllreq,
|
|
ffnetmsg,
|
|
ffsrbde,
|
|
ffsrintm,
|
|
ffdbbase;
|
|
|
|
type
|
|
{forward declarations}
|
|
TFFRemoteServerEngine = class;
|
|
{The TffRemoteServerEngine implements the TFFBaseServerEngine abstract
|
|
methods. It's method calls will initiate the process that will format
|
|
a message request to be sent to a remote server via a transport.
|
|
The TffRemoteServerEngine methods sometimes pass buffers without passing
|
|
the buffer length. However, the length must be known in order for the
|
|
message to be sent.
|
|
|
|
It is also possible for the TffRemoteServerEngine to be accessed by
|
|
multiple threads. We want to make sure that messages for one thread don't
|
|
wind up with another thread.
|
|
|
|
To handle cases such as these, the TffRemoteServerEngine needs to track
|
|
information specific to a cursor and client, respectively. To this
|
|
end we have created proxy classes to hold the information. For
|
|
example, a TffProxyCursor holds information specific to an open cursor.
|
|
A TffProxyClient holds information specific to an open client.
|
|
|
|
The TffRemoteServerEngine creates an instance of a proxy class when its
|
|
equivalent server-side object is opened. Instead of returning the
|
|
server-side object's ID to the object(s) using the remote engine, the
|
|
remote engine returns the pointers to its proxy objects. This scheme
|
|
allows TffRemoteServerEngine to derive a server-side ID from its proxy
|
|
object and allows it to maintain information required for its operation.
|
|
|
|
In general, all calls to remote server engine wind up calling a method on
|
|
a TffProxy class which in turn formats a request and sends it through
|
|
TffProxyClient.}
|
|
|
|
TFFProxyClientList = class;
|
|
TFFProxySession = class;
|
|
TFFProxySessionList = class;
|
|
TFFProxyDatabase = class;
|
|
TFFProxyDatabaseList = class;
|
|
TFFProxyCursor = class;
|
|
TFFProxyCursorList = class;
|
|
TffProxySQLStmt = class;
|
|
TffProxySQLStmtList = class;
|
|
{-End forward declarations}
|
|
|
|
{Creating/destroying and ownership issues.
|
|
The TFFProxyClient object will be created/destroyed and owned by it's
|
|
parent, a TFFRemoteServerEngine. The TFFRemoteServerEngine will be
|
|
responsible for keeping a list of the afore mentioned object.
|
|
|
|
The TFFProxySession object, and the TFFProxyDatabase object will be
|
|
created/destroyed and owned by it's parent, a TFFProxyClient. The
|
|
TFFProxyClient will be responsible for keeping a list of all instances
|
|
of the afore mentioned objects.
|
|
|
|
The TFFProxyCursor object will be created/destroyed and owned by
|
|
it's parent, a TFFProxyDatabase. The TFFProxyDatabase will be responsible
|
|
for keeping a list of all instances of the afore mentioned object.
|
|
|
|
The constructor for each of the client classes is resposible for
|
|
contacting the server, and retrieving an ID from the server. The parent
|
|
class will not manipulate the ServerID directly.
|
|
|
|
The destructor for each of the client classes is resposible for
|
|
tellint the server to release it's associated object.
|
|
|
|
If a proxy class "owns" any other classes then any owned classes must be
|
|
destroyed first.
|
|
|
|
In the end there should be no manipulation of ServerID's except in the
|
|
objects constructor. And no way to free a parent class without first
|
|
freeing dependent classes. }
|
|
|
|
|
|
{TFFProxyClient
|
|
The proxy client controls interaction between the remote server engine
|
|
and the transport. This class contains a message queue associated with
|
|
a specific client. All requests for data must go through this class'
|
|
ProcessRequest method. Instances where a reply from the server isn't
|
|
necessary can use the ProcessRequestNoReply method. }
|
|
|
|
|
|
TFFProxyClient = class(TffObject)
|
|
protected
|
|
pcSrClientID : TffClientID;
|
|
{An ID pointing to the associated TFFSrClient class on the server}
|
|
|
|
pcMsgQueue : TffDataMessageQueue;
|
|
{The message queue used to store replies to this client. }
|
|
|
|
pcCallbackMethod : TffReplyCallback;
|
|
{A Method pointer that will be passed to the transport when a
|
|
reply is requested.}
|
|
|
|
pcCurrentSession : TffProxySession;
|
|
{The current session as set by the SessionSetCurrent method}
|
|
|
|
pcDatabases : TFFProxyDatabaseList;
|
|
{The databases that are managed by the client}
|
|
|
|
pcForceClosed : Boolean;
|
|
|
|
pcTransport : TffBaseTransport;
|
|
{A reference to the RemoteServerEngine's transport. Added here for
|
|
purposes of speed, and readability.}
|
|
|
|
pcSessions : TFFProxySessionList;
|
|
{The sessions that are registered with the client. }
|
|
|
|
pcTimeout : Longint;
|
|
{The current timeout setting for the TFFBaseConnection Class. The
|
|
TFFBaseConnection class is resposible for updating this object when
|
|
it's published timeout value is changed.}
|
|
|
|
public
|
|
constructor Create(aTransport : TffBaseTransport;
|
|
aUserName : TFFName;
|
|
aPasswordHash : Longint;
|
|
aTimeOut : Longint);
|
|
destructor Destroy; override;
|
|
|
|
function IsReadOnly : Boolean;
|
|
|
|
function ProcessRequest(aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint;
|
|
aRequestDataType : TffNetMsgDataType;
|
|
var aReply : Pointer;
|
|
var aReplyLen : Longint;
|
|
aReplyType : TffNetMsgDataType) : TffResult;
|
|
{ Use the ProxessRequest method to submit a request that is routed to the
|
|
transport. This method does the following:
|
|
|
|
1. Calls TffBaseTransport.Request with transportID = 0 and cookie
|
|
equal to Pointer(Self). At this point, the calling thread is
|
|
blocked until a reply is received from the server or a timeout
|
|
occurs.
|
|
2. When the calling thread returns to this method, the reply has
|
|
been received and placed in the message queue by the
|
|
ProxyClientCallback procedure.
|
|
3. Verify the message is the type that we expected.
|
|
4. Put the message into the MessageQueue and exit.}
|
|
|
|
|
|
function ProcessRequestNoReply(aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint) : TffResult;
|
|
{ Use the ProxessRequestNoReply method to submit a request that is
|
|
routed to the transport. This method does the following:
|
|
|
|
1. Calls TffBaseTransport.Post with transportID = 0 and reply mode
|
|
to waituntilsent. At this point, the calling thread is
|
|
blocked until the request has been sent to the server.}
|
|
function DatabaseClose(aDatabase : TffProxyDatabase) : TffResult;
|
|
function DatabaseOpen(const aAlias : TffName;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID) : TffResult;
|
|
{Add a database to the pcDatabases list. The client will take
|
|
care of creating}
|
|
|
|
function DatabaseOpenNoAlias(const aPath : TffPath;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
function GetRebuildStatus(const aRebuildID : Longint;
|
|
var aIsPresent : Boolean;
|
|
var aStatus : TffRebuildStatus) : TffResult;
|
|
function SetTimeout(const aTimeout : Longint) : TffResult;
|
|
function SessionAdd(var aSessionID : TffSessionID;
|
|
const aTimeout : Longint) : TffResult;
|
|
{Add a session to the pcSessions list. The client will take
|
|
care of creating the TFFProxySession object, whose ID will
|
|
be returned via aSessionID.}
|
|
|
|
function SessionCloseInactiveTables : TffResult; {!!.06}
|
|
{ Close the inactive tables on the server. }
|
|
|
|
function SessionCount : Longint;
|
|
{Retrieve the number of sessions the client is managing.}
|
|
|
|
function SessionGetCurrent : TffProxySession;
|
|
{Retrieve the current session}
|
|
|
|
function SessionRemove(aSession : TFFProxySession) : TffResult;
|
|
{Remove the session from the list. The client will take destroy
|
|
the session, and remove it from the list}
|
|
|
|
function SessionSetCurrent(aSession : TFFProxySession) : TffResult;
|
|
{Set the current session}
|
|
|
|
function DatabaseAddAlias(const aAlias : TffName;
|
|
const aPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
function DatabaseAliasList(aList : TList) : TffResult;
|
|
function DatabaseChgAliasPath(const aAlias : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
function DatabaseDeleteAlias(const aAlias : TffName) : TffResult;
|
|
function DatabaseGetAliasPath(const aAlias : TffName;
|
|
var aPath : TffPath) : TffResult;
|
|
function DatabaseModifyAlias(const aAlias : TffName;
|
|
const aNewName : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
|
|
function GetServerDateTime(var aDateTime : TDateTime) : TffResult;
|
|
{begin !!.10}
|
|
function GetServerSystemTime(var aSystemTime : TSystemTime)
|
|
: TffResult;
|
|
function GetServerGUID(var aGUID : TGUID) : TffResult;
|
|
function GetServerID(var aUniqueID : TGUID) : TffResult;
|
|
function GetServerStatistics(var Stats : TffServerStatistics)
|
|
: TffResult;
|
|
function GetCommandHandlerStatistics(const CmdHandlerIdx : Integer;
|
|
var Stats : TffCommandHandlerStatistics)
|
|
: TffResult;
|
|
function GetTransportStatistics(const CmdHandlerIdx : Integer;
|
|
const Transportidx : Integer;
|
|
var Stats : TffTransportStatistics)
|
|
: TffResult;
|
|
{end !!.10}
|
|
|
|
|
|
{Begin !!.01}
|
|
function RemoteRestart : TffResult;
|
|
{ Tell the remote server to restart. }
|
|
|
|
function RemoteStart : TffResult;
|
|
{ Tell the remote server to startup. }
|
|
|
|
function RemoteStop : TffResult;
|
|
{ Tell the remote server to stop. }
|
|
{End !!.01}
|
|
|
|
{ReadOnly properties for the protected fields}
|
|
property CurrentSession : TFFProxySession
|
|
read SessionGetCurrent;
|
|
property Databases : TFFProxyDatabaseList
|
|
read pcDatabases;
|
|
property ForceClosed : Boolean
|
|
read pcForceClosed
|
|
write pcForceClosed;
|
|
property MsgQueue : TFFDataMessageQueue
|
|
read pcMsgQueue;
|
|
property Sessions : TFFProxySessionList
|
|
read pcSessions;
|
|
property SrClientID : TffClientID
|
|
read pcSrClientID;
|
|
property Transport : TFFBaseTransport
|
|
read pcTransport;
|
|
property Timeout : Longint
|
|
read pcTimeout;
|
|
end;
|
|
|
|
{List containing a reference for every ProxyClient owned by
|
|
a TFFRemoteServerEngine component.}
|
|
TFFProxyClientList = class(TffThreadList);
|
|
|
|
|
|
{The TFFProxySession is used primarily to keep track of the
|
|
the current Timeout setting, and the Server CursorID.
|
|
Unlike the TFFSession, the ProxySession does not manage a
|
|
set of Databases. TFFProxyDatabases, instead, are managed by
|
|
the ProxyClient class}
|
|
TFFProxySession = class(TFFObject)
|
|
protected
|
|
psSrSessionID : TFFSessionID;
|
|
{An ID pointing to the TFFSrSession object on the remote server}
|
|
|
|
psClient : TFFProxyClient;
|
|
{A reference to the client who owns this object}
|
|
|
|
psTimeout : Longint;
|
|
{Local storage for the current Session timeout setting. The TFFSession
|
|
object is resposible for keeping this value up to date.}
|
|
|
|
public
|
|
constructor Create(aClient : TFFProxyClient; aTimeout : Longint);
|
|
|
|
destructor Destroy; override;
|
|
|
|
function SetTimeout(aTimeout : Longint) : TffResult;
|
|
|
|
{ReadOnly properties for the protected fields}
|
|
property SrSessionID : TFFSessionID
|
|
read psSrSessionID;
|
|
property Client : TFFProxyClient
|
|
read psClient;
|
|
property Timeout : LongInt
|
|
read psTimeout;
|
|
end;
|
|
|
|
{List containing a reference for every ProxySesion owned by
|
|
a TFFProxyClient object.}
|
|
TFFProxySessionList = class(TffThreadList);
|
|
|
|
|
|
{The TFFProxyDatabase is responsible for basic Table maintenance. It also
|
|
keeps track of the the current Timeout setting, and the Server CursorID.
|
|
TFFProxyDatabase maintains a list of TFFProxyCursor objects.}
|
|
TFFProxyDatabase = class(TffObject)
|
|
protected
|
|
pdSrDatabaseID : TffDatabaseID;
|
|
{An ID pointing to the TffSrDatabase object on the remote server}
|
|
|
|
pdClient : TFFProxyClient;
|
|
{A reference to the client who owns this object}
|
|
|
|
pdInTrans : Boolean;
|
|
{Have we instantiated a tranaction? }
|
|
|
|
pdStmts : TffProxySQLStmtList;
|
|
{The SQL statements managed by this database}
|
|
|
|
pdTables : TFFProxyCursorList;
|
|
{The tables that are managed by the database}
|
|
|
|
pdTimeout : Longint;
|
|
{Local storage for the current Database timeout setting. The TFFDatabase
|
|
object is resposible for keeping this value up to date.}
|
|
public
|
|
constructor Create(aClient : TFFProxyClient;
|
|
aLocation : string;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
aIsAlias : Boolean);
|
|
destructor Destroy; override;
|
|
function GetDBFreeSpace(var aFreeSpace : Longint) : TffResult;
|
|
function QueryOpen(aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : longInt;
|
|
aStream : TStream;
|
|
var aFinalCursorID : TffCursorID) : TffResult;
|
|
function SetTimeout(const aTimeout : Longint) : TffResult;
|
|
function SQLAlloc(const aTimeout : longInt;
|
|
var aStmtID : TffSqlStmtID) : TffResult;
|
|
function SQLExecDirect(aQueryText : PChar;
|
|
aOpenMode : TffOpenMode;
|
|
aTimeout : longInt;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
function TableExists(const aTableName : TffTableName;
|
|
var aExists : Boolean) : TffResult;
|
|
function TableList(const aMask : TffFileNameExt;
|
|
aList : TList) : TffResult;
|
|
function TableLockedExclusive(const aTableName : TffTableName;
|
|
var aLocked : Boolean) : TffResult;
|
|
function TableAddIndex(const aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexDesc : TffIndexDescriptor) : TffResult;
|
|
function TableBuild(aOverWrite : Boolean;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aDictionary : TffDataDictionary) : TffResult;
|
|
function TableDelete(const aTableName : TffTableName) : TffResult;
|
|
function TableDropIndex(aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffDictItemName;
|
|
aIndexID : longint) : TffResult;
|
|
function TableEmpty(aCursorID : TffCursorID;
|
|
const aTableName : TffTableName) : TffResult;
|
|
function TableGetDictionary(const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aStream : TStream) : TffResult;
|
|
function TableClose(aCursor : TFFProxyCursor) : TffResult;
|
|
function TableOpen(const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
function TablePack(const aTableName : TffTableName;
|
|
var aRebuildID : Longint) : TffResult;
|
|
function TableRebuildIndex(const aTableName : TffTableName;
|
|
const aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
var aRebuildID : Longint) : TffResult;
|
|
function TableRename(const aOldName : TffName;
|
|
const aNewName : TffName) : TffResult;
|
|
function TableRestructure(const aTableName : TffTableName;
|
|
aDictionary : TffDataDictionary;
|
|
aFieldMap : TffStringList;
|
|
var aRebuildID : Longint) : TffResult;
|
|
function TransactionStart(aFailSafe : Boolean) : TffResult;
|
|
{Begin !!.10}
|
|
function TransactionStartWith(const aFailSafe : Boolean;
|
|
const aCursorIDs : TffPointerList) : TffResult;
|
|
{End !!.10}
|
|
function TransactionCommit : TffResult;
|
|
function TransactionRollback : TffResult;
|
|
|
|
property Client : TFFProxyClient
|
|
read pdClient;
|
|
property InTrans : Boolean
|
|
read pdInTrans;
|
|
property SrDatabaseID : TFFDatabaseID
|
|
read pdSrDatabaseID;
|
|
property Tables : TffProxyCursorList
|
|
read pdTables;
|
|
property Timeout : Longint
|
|
read pdTimeout;
|
|
end;
|
|
|
|
TFFProxyDatabaseList = class(TffThreadList);
|
|
|
|
TFFProxyCursor = class(TffObject)
|
|
protected
|
|
prSrCursorID : TffCursorID;
|
|
prClient : TFFProxyClient;
|
|
prForServer : Boolean;
|
|
prShareMode : TffShareMode;
|
|
prTableName : TFFTableName;
|
|
prTimeout : Longint;
|
|
prDatabase : TFFProxyDatabase;
|
|
|
|
{State Variables}
|
|
prDictionary : TffDataDictionary;
|
|
prIndexID : Longint;
|
|
prIndexName : string;
|
|
prIsSQLCursor : boolean;
|
|
prPhyRecSize : Longint;
|
|
protected
|
|
function prGetBookmarkSize : Longint;
|
|
public
|
|
constructor Create(aDatabase : TFFProxyDatabase;
|
|
aCursorID : TffCursorID; {used by CursorClone, otherwise set to 0}
|
|
aTableName : string;
|
|
aForServer : Boolean;
|
|
aIndexName : string;
|
|
aIndexID : Longint;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : LongInt;
|
|
aStream : TStream);
|
|
|
|
constructor CreateSQL(aDatabase : TffProxyDatabase;
|
|
aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : longInt;
|
|
aStream : TStream);
|
|
{ This constructor is used to construct a proxy cursor for an executed
|
|
SQL statement. }
|
|
|
|
destructor Destroy; override;
|
|
function BlobCreate(var aBlobNr : TFFInt64) : TFFResult;
|
|
function BLOBDelete(aBlobNr : TFFInt64) : TffResult;
|
|
function BLOBFree(aBlobNr : TffInt64;
|
|
aReadOnly : Boolean) : TFFResult;
|
|
function BLOBGetLength(aBlobNr : TffInt64;
|
|
var aLength : Longint) : TffResult;
|
|
{Begin !!.03}
|
|
function BLOBListSegments(aBLOBNr : TffInt64;
|
|
aStream : TStream) : TffResult;
|
|
{End !!.03}
|
|
function BLOBRead(aBlobNr : TffInt64;
|
|
aOffset : TffWord32; {!!.06}
|
|
aLen : TffWord32; {!!.06}
|
|
var aBLOB;
|
|
var aBytesRead : TffWord32) {!!.06}
|
|
: TffResult;
|
|
function BLOBTruncate(aBlobNr : TffInt64;
|
|
aBLOBLength : Longint) : TffResult;
|
|
function BLOBWrite(aBlobNr : TffInt64;
|
|
aOffset : Longint;
|
|
aLen : Longint;
|
|
var aBLOB) : TFFResult;
|
|
function CursorClone(aOpenMode : TFFOpenMode;
|
|
var aNewCursorID : TFFCursorID) : TFFResult;
|
|
function CompareBookmarks(aBookmark1 : PffByteArray;
|
|
aBookmark2 : PffByteArray;
|
|
var aCompResult : Longint) : TffResult;
|
|
function CopyRecords(aSrcCursor : TffProxyCursor; {!!.02}
|
|
aCopyBLOBs : Boolean) : TffResult; {!!.02}
|
|
function DeleteRecords : TffResult; {!!.06}
|
|
function GetBookmark(aBookmark : PffByteArray) : TffResult;
|
|
function GetBookmarkSize(var aSize : Longint) : TffResult;
|
|
{Begin !!.03}
|
|
function ListBLOBFreeSpace(const aInMemory : Boolean;
|
|
aStream : TStream) : TffResult;
|
|
{End !!.03}
|
|
function OverrideFilter(aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult;
|
|
function ResetRange : TffResult;
|
|
function RestoreFilter : TffResult;
|
|
function SetFilter(aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult;
|
|
function SetRange(aDirectKey : Boolean;
|
|
aFieldCount1 : Longint;
|
|
aPartialLen1 : Longint;
|
|
aKeyData1 : PffByteArray;
|
|
aKeyIncl1 : Boolean;
|
|
aFieldCount2 : Longint;
|
|
aPartialLen2 : Longint;
|
|
aKeyData2 : PffByteArray;
|
|
aKeyIncl2 : Boolean) : TffResult;
|
|
function SetTimeout(aTimeout : Longint) : TffResult;
|
|
function SetToBegin : TffResult;
|
|
function SetToBookmark(aBookmark : PffByteArray) : TffResult;
|
|
function SetToCursor(aSourceCursor : TFFProxyCursor) : TffResult;
|
|
function SetToEnd : TffResult;
|
|
function SetToKey(aSearchAction : TffSearchKeyAction;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray) : TffResult;
|
|
function SwitchToIndex(aIndexName : TffDictItemName;
|
|
aIndexID : Longint;
|
|
aPosnOnRec : Boolean) : TffResult;
|
|
function FileBLOBAdd(const aFileName : TffFullFileName;
|
|
var aBlobNr : TffInt64) : TffResult;
|
|
function RecordDelete(aData : PffByteArray) : TffResult;
|
|
function RecordDeleteBatch(aBMCount : Longint;
|
|
aBMLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray) : TffResult;
|
|
function RecordExtractKey(aData : PffByteArray;
|
|
aKey : PffByteArray) : TffResult;
|
|
function RecordGet(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
function RecordGetBatch(aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
var aRecRead : Longint;
|
|
aData : PffByteArray;
|
|
var aError : TffResult) : TffResult;
|
|
function RecordGetForKey(aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray;
|
|
aData : PffByteArray;
|
|
aFirstCall : Boolean) : TffResult;
|
|
function RecordGetNext(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
function RecordGetPrior(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
function RecordInsert(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
function RecordInsertBatch(aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray) : TffResult;
|
|
function RecordIsLocked(aLockType : TffLockType;
|
|
var aIsLocked : boolean) : TffResult;
|
|
function RecordModify(aData : PffByteArray;
|
|
aRelLock : Boolean) : TffResult;
|
|
function RecordRelLock(aAllLocks : Boolean) : TffResult;
|
|
function TableGetAutoInc(var aValue : TffWord32) : TffResult;
|
|
function TableGetRecCount(var aRecCount : Longint) : TffResult;
|
|
function TableGetRecCountAsync(var aTaskID : Longint) : TffResult; {!!.07}
|
|
function TableIsLocked(aLockType : TffLockType;
|
|
var aIsLocked : Boolean) : TffResult;
|
|
function TableLockAcquire(aLockType : TffLockType) : TffResult;
|
|
function TableLockRelease(aAllLocks : Boolean) : TffResult;
|
|
function TableSetAutoInc(aValue : TffWord32) : TffResult;
|
|
|
|
property Client : TFFProxyClient
|
|
read prClient;
|
|
property SrCursorID : TffCursorID
|
|
read prSrCursorID;
|
|
property Timeout : Longint
|
|
read prTimeout;
|
|
property BookmarkSize : longint
|
|
read prGetBookmarkSize;
|
|
property Database : TFFProxyDatabase
|
|
read prDatabase;
|
|
property Dictionary : TffDataDictionary
|
|
read prDictionary;
|
|
property IndexID : Longint
|
|
read prIndexID;
|
|
property PhysicalRecordSize : Longint
|
|
read prPhyRecSize;
|
|
|
|
end;
|
|
|
|
TFFProxyCursorList = class(TffThreadList);
|
|
|
|
TffProxySQLStmt = class(TffObject)
|
|
protected {private}
|
|
|
|
psClient : TffProxyClient;
|
|
{ The proxy client through which requests are routed. }
|
|
|
|
psDatabase : TffProxyDatabase;
|
|
{ The proxy database with which the SQL statement is associated. }
|
|
|
|
psSrStmtID : TffSqlStmtID;
|
|
{ The actual statement ID. }
|
|
|
|
psTimeout : longInt;
|
|
{ The SQL statement's timeout (in milliseconds). }
|
|
|
|
public
|
|
{creation/destruction}
|
|
constructor Create(aDatabase : TffProxyDatabase; const aTimeout : longInt);
|
|
destructor Destroy; override;
|
|
|
|
function Exec(aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
|
|
function Prepare(aQueryText: PChar; aStream : TStream) : TffResult;
|
|
|
|
function SetParams(aNumParams : Word;
|
|
aParamDescs : Pointer;
|
|
aDataBuffer : PffByteArray;
|
|
aDataLen : Longint;
|
|
aStream : TStream) : TffResult;
|
|
|
|
property Database : TffProxyDatabase read psDatabase;
|
|
|
|
property SrStmtID : TffSqlStmtID read psSrStmtID;
|
|
{ The statement ID returned by the server engine. }
|
|
|
|
end;
|
|
|
|
TffProxySQLStmtList = class(TffThreadList);
|
|
|
|
TFFRemoteServerEngine = class(TffIntermediateServerEngine)
|
|
private
|
|
protected {private}
|
|
rsClientList : TFFProxyClientList;
|
|
rsTimeout : TffWord32;
|
|
rsTransport : TffBaseTransport;
|
|
{Begin !!.06}
|
|
function ProcessRequest(aClientID : TffClientID;
|
|
aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint;
|
|
aRequestDataType : TffNetMsgDataType;
|
|
var aReply : Pointer;
|
|
var aReplyLen : Longint;
|
|
aReplyType : TffNetMsgDataType) : TffResult; override;
|
|
{ Backdoor method for sending a request to a server engine.
|
|
Should only be implemented by remote server engines. }
|
|
|
|
function ProcessRequestNoReply(aClientID : TffClientID;
|
|
aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint ) : TffResult; override;
|
|
{ Backdoor method for sending a request, no reply expected, to a
|
|
server engine. Should only be implemented by remote server engines. }
|
|
{End !!.06}
|
|
procedure rsSetTransport(const Value : TFFBaseTransport);
|
|
// protected {!!.01 - Start - Made public}
|
|
// {validation and checking}
|
|
// function CheckClientIDAndGet(aClientID : TffClientID;
|
|
// var aClient : TffProxyClient) : TffResult;
|
|
// function CheckSessionIDAndGet(aClientID : TffClientID;
|
|
// aSessionID : TffSessionID;
|
|
// var aClient : TffProxyClient;
|
|
// var aSession : TffProxySession) : TffResult;
|
|
// function CheckDatabaseIDAndGet(aDatabaseID : TffDatabaseID;
|
|
// var aDatabase : TffProxyDatabase) : TffResult;
|
|
// {-Find the database specified by aDatabaseID. }
|
|
//
|
|
// function CheckCursorIDAndGet(aCursorID : TffCursorID;
|
|
// var aCursor : TffProxyCursor) : TffResult;
|
|
// {-Find the cursor specified by aCursorID. }
|
|
//
|
|
// function CheckStmtIDAndGet(aStmtID : TffSqlStmtID;
|
|
// var aStmt : TffProxySQLStmt) : TffResult;
|
|
// {-Find the statement specified by aStmtID. } {!!.01 - End}
|
|
|
|
protected
|
|
{State methods}
|
|
procedure scInitialize; override;
|
|
procedure scPrepareForShutdown; override;
|
|
procedure scShutdown; override;
|
|
procedure scStartup; override;
|
|
function bseGetAutoSaveCfg : Boolean; override;
|
|
function bseGetReadOnly : Boolean; override;
|
|
procedure bseSetAutoSaveCfg(aValue : Boolean); override; {!!.01}
|
|
procedure bseSetReadOnly(aValue : Boolean); override; {!!.01}
|
|
public
|
|
{Begin !!.07}
|
|
{ Event logging }
|
|
procedure Log(const aMsg : string); override;
|
|
{-Use this method to log a string to the event log. }
|
|
|
|
procedure LogAll(const Msgs : array of string); override;
|
|
{-Use this method to log multiple strings to the event log. }
|
|
|
|
procedure LogFmt(const aMsg : string; args : array of const); override;
|
|
{-Use this method to log a formatted string to the event log. }
|
|
{End !!.07}
|
|
|
|
{Begin !!.01 - moved from protected section}
|
|
{validation and checking}
|
|
function CheckClientIDAndGet(aClientID : TffClientID;
|
|
var aClient : TffProxyClient) : TffResult;
|
|
function CheckSessionIDAndGet(aClientID : TffClientID;
|
|
aSessionID : TffSessionID;
|
|
var aClient : TffProxyClient;
|
|
var aSession : TffProxySession) : TffResult;
|
|
function CheckDatabaseIDAndGet(aDatabaseID : TffDatabaseID;
|
|
var aDatabase : TffProxyDatabase) : TffResult;
|
|
{-Find the database specified by aDatabaseID. }
|
|
|
|
function CheckCursorIDAndGet(aCursorID : TffCursorID;
|
|
var aCursor : TffProxyCursor) : TffResult;
|
|
{-Find the cursor specified by aCursorID. }
|
|
|
|
function CheckStmtIDAndGet(aStmtID : TffSqlStmtID;
|
|
var aStmt : TffProxySQLStmt) : TffResult;
|
|
{-Find the statement specified by aStmtID. }
|
|
{End !!.01}
|
|
|
|
{creation/destruction}
|
|
constructor Create(aOwner : TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure FFNotificationEx(const AOp : Byte; AFrom : TffComponent;
|
|
const AData : TffWord32); override;
|
|
|
|
function GetDefaultClient : TFFProxyClient;
|
|
|
|
procedure GetServerNames(aList : TStrings;
|
|
aTimeout : Longint); override;
|
|
|
|
procedure ForceClosing(const aClientID : TffClientID);
|
|
|
|
{Begin !!.01}
|
|
function RemoteRestart(const aClientID : TffClientID) : TffResult;
|
|
{ Tell the remote server to shutdown and startup. }
|
|
|
|
function RemoteStart(const aClientID : TffClientID) : TffResult;
|
|
{ Tell the remote server to startup. Only works if the remote server
|
|
is in a stopped state (i.e., transports & cmd handlers still
|
|
listening. }
|
|
|
|
function RemoteStop(const aClientID : TffClientID) : TffResult;
|
|
{ Tell the remote server to stop. The server engine shuts down but
|
|
the transport and cmd handlers will still be listening. }
|
|
{End !!.01}
|
|
|
|
{transaction tracking}
|
|
function TransactionCommit(const aDatabaseID : TffDatabaseID
|
|
) : TffResult; override;
|
|
function TransactionRollback(const aDatabaseID : TffDatabaseID
|
|
) : TffResult; override;
|
|
function TransactionStart(const aDatabaseID : TffDatabaseID;
|
|
const aFailSafe : Boolean
|
|
) : TffResult; override;
|
|
{Begin !!.10}
|
|
function TransactionStartWith(const aDatabaseID : TffDatabaseID;
|
|
const aFailSafe : Boolean;
|
|
const aCursorIDs : TffPointerList
|
|
) : TffResult; override;
|
|
{End !!.10}
|
|
|
|
{client related stuff}
|
|
function ClientAdd(var aClientID : TffClientID;
|
|
const aClientName : TffNetName;
|
|
const aUserID : TffName;
|
|
const aTimeout : Longint;
|
|
var aHash : TffWord32) : TffResult; override;
|
|
{Begin !!.11}
|
|
function ClientAddEx(var aClientID : TffClientID;
|
|
const aClientName : TffNetName;
|
|
const aUserID : TffName;
|
|
const aTimeout : Longint;
|
|
const aClientVersion : Longint;
|
|
var aHash : TffWord32) : TffResult; override;
|
|
{ Same as ClientAdd but client version is supplied via the aClientVersion
|
|
parameter. }
|
|
{End !!.11}
|
|
function ClientRemove(aClientID : TffClientID) : TffResult; override;
|
|
function ClientSetTimeout(const aClientID : TffClientID;
|
|
const aTimeout : longInt) : TffResult; override;
|
|
|
|
|
|
{client session related stuff}
|
|
function SessionAdd(const aClientID : TffClientID;
|
|
const aTimeout : Longint;
|
|
var aSessionID : TffSessionID) : TffResult; override;
|
|
function SessionCloseInactiveTables(aClientID : TffClientID) : TffResult; override; {!!.06}
|
|
function SessionCount(aClientID : TffClientID;
|
|
var aCount : Longint) : TffResult; override;
|
|
function SessionGetCurrent(aClientID : TffClientID;
|
|
var aSessionID : TffSessionID
|
|
) : TffResult; override;
|
|
function SessionRemove(aClientID : TffClientID;
|
|
aSessionID : TffSessionID) : TffResult; override;
|
|
function SessionSetTimeout(const aClientID : TffClientID;
|
|
const aSessionID : TffSessionID;
|
|
const aTimeout : Longint) : TffResult; override;
|
|
function SessionSetCurrent(aClientID : TffClientID;
|
|
aSessionID : TffSessionID
|
|
) : TffResult; override;
|
|
|
|
{database related stuff}
|
|
function DatabaseAddAlias(const aAlias : TffName;
|
|
const aPath : TffPath;
|
|
aCheckSpace : Boolean; {!!.11}
|
|
const aClientID : TffClientID)
|
|
: TffResult; override;
|
|
function DatabaseAliasList(aList : TList;
|
|
aClientID : TffClientID)
|
|
: TffResult; override;
|
|
function RecoveryAliasList(aList : TList;
|
|
aClientID : TffClientID)
|
|
: TffResult; override;
|
|
function DatabaseChgAliasPath(aAlias : TffName;
|
|
aNewPath : TffPath;
|
|
aCheckSpace : Boolean; {!!.11}
|
|
aClientID : TffClientID)
|
|
: TffResult; override;
|
|
function DatabaseClose(aDatabaseID : TffDatabaseID) : TffResult; override;
|
|
function DatabaseDeleteAlias(aAlias : TffName;
|
|
aClientID : TffClientID) : TffResult; override;
|
|
function DatabaseGetAliasPath(aAlias : TffName;
|
|
var aPath : TffPath;
|
|
aClientID : TffClientID) : TffResult; override;
|
|
function DatabaseGetFreeSpace(const aDatabaseID : TffDatabaseID;
|
|
var aFreeSpace : Longint) : TffResult; override;
|
|
function DatabaseModifyAlias(const aClientID : TffClientID;
|
|
const aAlias : TffName;
|
|
const aNewName : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult; override;
|
|
function DatabaseOpen(aClientID : TffClientID;
|
|
const aAlias : TffName;
|
|
const aOpenMode : TffOpenMode;
|
|
const aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID) : TffResult; override;
|
|
function DatabaseOpenNoAlias(aClientID : TffClientID;
|
|
const aPath : TffPath;
|
|
const aOpenMode : TffOpenMode;
|
|
const aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID
|
|
) : TffResult; override;
|
|
function DatabaseSetTimeout(const aDatabaseID : TffDatabaseID;
|
|
const aTimeout : Longint) : TffResult; override;
|
|
function DatabaseTableExists(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aExists : Boolean) : TffResult; override;
|
|
function DatabaseTableList(aDatabaseID : TffDatabaseID;
|
|
const aMask : TffFileNameExt;
|
|
aList : TList) : TffResult; override;
|
|
function DatabaseTableLockedExclusive(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aLocked : Boolean) : TffResult; override;
|
|
|
|
{rebuild status related stuff}
|
|
function RebuildGetStatus(aRebuildID : longint;
|
|
const aClientID : TffClientID;
|
|
var aIsPresent : Boolean;
|
|
var aStatus : TffRebuildStatus
|
|
) : TffResult; override;
|
|
|
|
{table related stuff}
|
|
function TableAddIndex(const aDatabaseID : TffDatabaseID;
|
|
const aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexDesc : TffIndexDescriptor
|
|
) : TffResult; override;
|
|
function TableBuild(aDatabaseID : TffDatabaseID;
|
|
aOverWrite : Boolean;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aDictionary : TffDataDictionary
|
|
) : TffResult; override;
|
|
function TableDelete(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName) : TffResult; override;
|
|
function TableDropIndex(aDatabaseID : TffDatabaseID;
|
|
aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffDictItemName;
|
|
aIndexID : longint) : TffResult; override;
|
|
function TableEmpty(aDatabaseID : TffDatabaseID;
|
|
aCursorID : TffCursorID;
|
|
const aTableName : TffTableName) : TffResult; override;
|
|
function TableGetAutoInc(aCursorID : TffCursorID;
|
|
var aValue : TffWord32) : TffResult; override;
|
|
function TableGetDictionary(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aStream : TStream) : TffResult; override;
|
|
function TableGetRecCount(aCursorID : TffCursorID;
|
|
var aRecCount : longint) : TffResult; override;
|
|
function TableGetRecCountAsync(aCursorID : TffCursorID; {!!.07}
|
|
var aTaskID : Longint) : TffResult; override; {!!.07}
|
|
function TableOpen(const aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
const aForServer : Boolean;
|
|
const aIndexName : TffName;
|
|
aIndexID : longint;
|
|
const aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult; override;
|
|
function TablePack(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aRebuildID : longint) : TffResult; override;
|
|
function TableRebuildIndex(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffName;
|
|
aIndexID : longint;
|
|
var aRebuildID : longint) : TffResult; override;
|
|
function TableRename(aDatabaseID : TffDatabaseID;
|
|
const aOldName : TffName;
|
|
const aNewName : TffName) : TffResult; override;
|
|
function TableRestructure(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
aDictionary : TffDataDictionary;
|
|
aFieldMap : TffStringList;
|
|
var aRebuildID : longint) : TffResult; override;
|
|
function TableSetAutoInc(aCursorID : TffCursorID;
|
|
aValue : TffWord32) : TffResult; override;
|
|
{Begin !!.11}
|
|
function TableVersion(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aVersion : Longint) : TffResult; override;
|
|
{End !!.11}
|
|
|
|
{table locks via cursor}
|
|
function TableIsLocked(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
var aIsLocked : Boolean) : TffResult; override;
|
|
function TableLockAcquire(aCursorID : TffCursorID;
|
|
aLockType : TffLockType) : TffResult; override;
|
|
function TableLockRelease(aCursorID : TffCursorID;
|
|
aAllLocks : Boolean) : TffResult; override;
|
|
|
|
{cursor stuff}
|
|
function CursorClone(aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
var aNewCursorID : TffCursorID) : TffResult; override;
|
|
function CursorClose(aCursorID : TffCursorID) : TffResult; override;
|
|
function CursorCompareBookmarks(aCursorID : TffCursorID;
|
|
aBookmark1,
|
|
aBookmark2 : PffByteArray;
|
|
var aCompResult : longint) : TffResult; override;
|
|
{Begin !!.02}
|
|
function CursorCopyRecords(aSrcCursorID,
|
|
aDestCursorID : TffCursorID;
|
|
aCopyBLOBs : Boolean) : TffResult; override;
|
|
{End !!.02}
|
|
function CursorDeleteRecords(aCursorID : TffCursorID) : TffResult; override; {!!.06}
|
|
function CursorGetBookmark(aCursorID : TffCursorID;
|
|
aBookmark : PffByteArray) : TffResult; override;
|
|
|
|
function CursorGetBookmarkSize(aCursorID : TffCursorID;
|
|
var aSize : Longint) : TffResult; override;
|
|
{Begin !!.03}
|
|
function CursorListBLOBFreeSpace(aCursorID : TffCursorID;
|
|
const aInMemory : Boolean;
|
|
aStream : TStream) : TffResult; override;
|
|
{End !!.03}
|
|
function CursorOverrideFilter(aCursorID : Longint;
|
|
aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult; override;
|
|
function CursorResetRange(aCursorID : TffCursorID) : TffResult; override;
|
|
function CursorRestoreFilter(aCursorID : longInt) : TffResult; override;
|
|
function CursorSetRange(aCursorID : TffCursorID;
|
|
aDirectKey : Boolean;
|
|
aFieldCount1 : Longint;
|
|
aPartialLen1 : Longint;
|
|
aKeyData1 : PffByteArray;
|
|
aKeyIncl1 : Boolean;
|
|
aFieldCount2 : Longint;
|
|
aPartialLen2 : Longint;
|
|
aKeyData2 : PffByteArray;
|
|
aKeyIncl2 : Boolean) : TffResult; override;
|
|
function CursorSetTimeout(const aCursorID : TffCursorID;
|
|
const aTimeout : Longint) : TffResult; override;
|
|
function CursorSetToBegin(aCursorID : TffCursorID) : TffResult; override;
|
|
function CursorSetToBookmark(aCursorID : TffCursorID;
|
|
aBookmark : PffByteArray
|
|
) : TffResult; override;
|
|
function CursorSetToCursor(aDestCursorID : TffCursorID;
|
|
aSrcCursorID : TffCursorID
|
|
) : TffResult; override;
|
|
function CursorSetToEnd(aCursorID : TffCursorID) : TffResult; override;
|
|
function CursorSetToKey(aCursorID : TffCursorID;
|
|
aSearchAction : TffSearchKeyAction;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray
|
|
) : TffResult; override;
|
|
function CursorSwitchToIndex(aCursorID : TffCursorID;
|
|
aIndexName : TffDictItemName;
|
|
aIndexID : Longint;
|
|
aPosnOnRec : Boolean) : TffResult; override;
|
|
function CursorSetFilter(aCursorID : TffCursorID;
|
|
aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult; override;
|
|
|
|
{record stuff}
|
|
function RecordDelete(aCursorID : TffCursorID;
|
|
aData : PffByteArray) : TffResult; override;
|
|
function RecordDeleteBatch(aCursorID : TffCursorID;
|
|
aBMCount : Longint;
|
|
aBMLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray) : TffResult; override;
|
|
function RecordExtractKey(aCursorID : TffCursorID;
|
|
aData : PffByteArray;
|
|
aKey : PffByteArray) : TffResult; override;
|
|
function RecordGet(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult; override;
|
|
function RecordGetBatch(aCursorID : TffCursorID;
|
|
aRecCount : longint;
|
|
aRecLen : longint;
|
|
var aRecRead : longint;
|
|
aData : PffByteArray;
|
|
var aError : TffResult) : TffResult; override;
|
|
function RecordGetForKey(aCursorID : TffCursorID;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray;
|
|
aData : PffByteArray;
|
|
aFirstCall : Boolean
|
|
) : TffResult; override;
|
|
function RecordGetNext(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult; override;
|
|
function RecordGetPrior(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult; override;
|
|
function RecordInsert(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult; override;
|
|
function RecordInsertBatch(aCursorID : TffCursorID;
|
|
aRecCount : longint;
|
|
aRecLen : longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray) : TffResult; override;
|
|
function RecordIsLocked(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
var aIsLocked : boolean) : TffResult; override;
|
|
function RecordModify(aCursorID : TffCursorID;
|
|
aData : PffByteArray;
|
|
aRelLock : Boolean) : TffResult; override;
|
|
function RecordRelLock(aCursorID : TffCursorID;
|
|
aAllLocks : Boolean) : TffResult; override;
|
|
|
|
{BLOB stuff}
|
|
function BLOBCreate(aCursorID : TffCursorID;
|
|
var aBlobNr : TffInt64) : TffResult; override;
|
|
function BLOBDelete(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64) : TffResult; override;
|
|
{Begin !!.03}
|
|
function BLOBListSegments(aCursorID : TffCursorID;
|
|
aBLOBNr : TffInt64;
|
|
aStream : TStream) : TffResult; override;
|
|
{End !!.03}
|
|
function BLOBRead(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
aOffset : TffWord32; {!!.06}
|
|
aLen : TffWord32; {!!.06}
|
|
var aBLOB;
|
|
var aBytesRead : TffWord32) {!!.06}
|
|
: TffResult; override;
|
|
function BLOBFree(aCursorID : TffCursorID; aBlobNr : TffInt64;
|
|
readOnly : Boolean) : TffResult; override;
|
|
function BLOBGetLength(aCursorID : TffCursorID; aBlobNr : TffInt64;
|
|
var aLength : longint) : TffResult; override;
|
|
function BLOBTruncate(aCursorID : TffCursorID; aBlobNr : TffInt64;
|
|
aBLOBLength : longint) : TffResult; override;
|
|
function BLOBWrite(aCursorID : TffCursorID; aBlobNr : TffInt64;
|
|
aOffset : longint;
|
|
aLen : longint;
|
|
var aBLOB) : TffResult; override;
|
|
function FileBLOBAdd(aCursorID : TffCursorID;
|
|
const aFileName : TffFullFileName;
|
|
var aBlobNr : TffInt64) : TffResult; override;
|
|
|
|
{query stuff}
|
|
function SQLAlloc(aClientID : TffClientID;
|
|
aDatabaseID : TffDatabaseID;
|
|
aTimeout : longInt;
|
|
var aStmtID : TffSqlStmtID) : TffResult; override;
|
|
function SQLExec(aStmtID : TffSqlStmtID;
|
|
aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult; override;
|
|
function SQLExecDirect(aClientID : TffClientID;
|
|
aDatabaseID : TffDatabaseID;
|
|
aQueryText : PChar;
|
|
aTimeout : longInt;
|
|
aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult; override;
|
|
function SQLFree(aStmtID : TffSqlStmtID) : TffResult; override;
|
|
function SQLPrepare(aStmtID : TffSqlStmtID;
|
|
aQueryText : PChar;
|
|
aStream : TStream) : TffResult; override;
|
|
function SQLSetParams(aStmtID : TffSqlStmtID;
|
|
aNumParams : word;
|
|
aParamDescs : pointer;
|
|
aDataBuffer : PffByteArray;
|
|
aDataLen : Longint;
|
|
aStream : TStream) : TffResult; override;
|
|
|
|
{misc stuff}
|
|
function GetServerDateTime(var aDateTime : TDateTime
|
|
) : TffResult; override;
|
|
{begin !!.07}
|
|
function GetServerSystemTime(var aSystemTime : TSystemTime) : TffResult; override;
|
|
function GetServerGUID(var aGUID : TGUID) : TffResult; override;
|
|
function GetServerID(var aUniqueID : TGUID) : TffResult; override;
|
|
function GetServerStatistics(var Stats : TffServerStatistics) : TffResult; override;
|
|
function GetCommandHandlerStatistics(const CmdHandlerIdx : Integer;
|
|
var Stats : TffCommandHandlerStatistics) : TffResult; override;
|
|
function GetTransportStatistics(const CmdHandlerIdx : Integer;
|
|
const TransportIdx : Integer;
|
|
var Stats : TffTransportStatistics) : TffResult; override;
|
|
{end !!.07}
|
|
|
|
|
|
{properties}
|
|
property ClientList : TFFProxyClientList
|
|
read rsClientList;
|
|
|
|
property TimeOut : TFFWord32
|
|
read rsTimeout write rsTimeout;
|
|
|
|
published
|
|
property Transport : TFFBaseTransport
|
|
read rsTransport
|
|
write rsSetTransport;
|
|
|
|
end;
|
|
|
|
{Callback method used by the transport to notify us when the request is
|
|
complete.}
|
|
procedure ProxyRequestCallback(aMsgID : Longint;
|
|
aErrorCode : TffResult;
|
|
aReply : Pointer;
|
|
aReplyLen : Longint;
|
|
aReplyCookie : Longint);
|
|
|
|
var
|
|
RemoteServerEngines : TFFThreadList;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ActiveX,
|
|
ffsqlbas;
|
|
|
|
{--Internal helper routines--}
|
|
function ResultOK(aResult : TffResult) : Boolean;
|
|
begin
|
|
Result := aResult = DBIERR_NONE;
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
|
|
{--Callback routine--}
|
|
procedure ProxyRequestCallback(aMsgID : Longint;
|
|
aErrorCode : TffResult;
|
|
aReply : Pointer;
|
|
aReplyLen : Longint;
|
|
aReplyCookie : Longint);
|
|
var
|
|
Client : TFFProxyClient absolute aReplyCookie;
|
|
begin
|
|
{ hand-off the response from the transport to the ProxyClient }
|
|
Client.pcMsgQueue.Append(aMsgID,
|
|
aReplyCookie,
|
|
0, {RequestID}
|
|
0, {Timeout}
|
|
aErrorCode,
|
|
aReply,
|
|
aReplyLen,
|
|
aReplyLen);
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
|
|
|
|
{-TffProxyClient---------------------------------------------------------------}
|
|
constructor TFFProxyClient.Create(aTransport : TffBaseTransport;
|
|
aUserName : TFFName;
|
|
aPasswordHash : Longint;
|
|
aTimeOut : Longint);
|
|
begin
|
|
inherited Create;
|
|
|
|
{Initialize internals}
|
|
pcSrClientID := 0;
|
|
pcCurrentSession := nil;
|
|
pcForceClosed := False;
|
|
|
|
pcTransport := aTransport;
|
|
pcTimeout := aTimeOut;
|
|
|
|
{Create internal classes}
|
|
pcMsgQueue := TffDataMessageQueue.Create;
|
|
pcSessions := TFFProxySessionList.Create;
|
|
pcDatabases := TFFProxyDatabaseList.Create;
|
|
|
|
{Set the CallbackMethod that will be used by the transport to return data}
|
|
pcCallbackMethod := ProxyRequestCallback;
|
|
|
|
{Let the ServerEngine know that we are here. Set our SrClientID for later
|
|
reference, as we will need it often.}
|
|
Check(pcTransport.EstablishConnection(aUserName,
|
|
aPasswordHash,
|
|
pcTimeOut,
|
|
pcSrClientID));
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseAddAlias(const aAlias : TffName;
|
|
const aPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
var
|
|
Request : TffnmDatabaseAddAliasReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize the request record }
|
|
Request.Alias := aAlias;
|
|
Request.Path := aPath;
|
|
Request.CheckDisk := aCheckSpace; {!!.11}
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmDatabaseAddAlias,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
{ Calling ffnmDatabaseAddAlias only returns an error code to Result. }
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseAliasList(aList: TList) : TffResult;
|
|
var
|
|
Stream : TMemoryStream;
|
|
ReplyLen : Longint;
|
|
Count : Longint;
|
|
AliasDes : PffAliasDescriptor;
|
|
DesSize : Longint;
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
try
|
|
{ We have no data to send. }
|
|
Result := ProcessRequest(ffnmDatabaseAliasList,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Stream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
if ResultOK(Result) then begin
|
|
aList.Clear;
|
|
Stream.Position := 0;
|
|
DesSize := SizeOf(TffAliasDescriptor);
|
|
|
|
for Count := 1 to (ReplyLen div DesSize) do begin
|
|
{ Move the alias data from the stream, to a PffAliasDescriptor. Each
|
|
descriptor will be an entry in aList. The caller must free this
|
|
data when it is done using it. }
|
|
FFGetMem(AliasDes, DesSize);
|
|
Stream.Read(AliasDes^, DesSize);
|
|
aList.Add(AliasDes);
|
|
end;
|
|
end;
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseChgAliasPath(const aAlias : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
var
|
|
Request : TffnmDatabaseChgAliasPathReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize the request record }
|
|
Request.Alias := aAlias;
|
|
Request.NewPath := aNewPath;
|
|
Request.CheckDisk := aCheckSpace; {!!.11}
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmDatabaseChgAliasPath,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
{ Calling ffnmDatabaseChgAliasPath only returns an error code to Result. }
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseClose(aDatabase : TffProxyDatabase) : TffResult;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
with pcDatabases.BeginWrite do
|
|
try
|
|
Delete(aDatabase); {!!.01}
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
aDatabase.Free;
|
|
aDatabase := nil;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseDeleteAlias(const aAlias : TffName) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseDeleteAliasReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize the request record }
|
|
Request.Alias := aAlias;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmDatabaseDeleteAlias,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
{ Calling ffnmDatabaseDeleteAlias only returns an error code to Result. }
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseGetAliasPath(const aAlias : TffName;
|
|
var aPath : TffPath
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseGetAliasPathReq;
|
|
Reply : PffnmDatabaseGetAliasPathRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize the request record }
|
|
Request.Alias := aAlias;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmDatabaseGetAliasPath,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aPath := Reply^.Path;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyClient.DatabaseModifyAlias(const aAlias : TffName;
|
|
const aNewName : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
var
|
|
Request : TffnmDatabaseModifyAliasReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize the request record }
|
|
Request.ClientID := SrClientID;
|
|
Request.Alias := aAlias;
|
|
Request.NewName := aNewName;
|
|
Request.NewPath := aNewPath;
|
|
Request.CheckDisk := aCheckSpace; {!!.11}
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmDatabaseModifyAlias,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseOpen(const aAlias : TffName;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID)
|
|
: TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
ListItem : TffIntListItem;
|
|
begin
|
|
Database := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Database := TFFProxyDatabase.Create(Self,
|
|
aAlias,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
True);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Database) then begin
|
|
{Add Database to the internal list}
|
|
ListItem := TffIntListItem.Create(Longint(Database));
|
|
with pcDatabases.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aDatabaseID := Longint(Database);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.DatabaseOpenNoAlias(const aPath : TffPath;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
ListItem : TffIntListItem;
|
|
begin
|
|
Database := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Database := TFFProxyDatabase.Create(Self,
|
|
aPath,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
False);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Database) then begin
|
|
{Add Database to the internal list}
|
|
ListItem := TffIntListItem.Create(Longint(Database));
|
|
with pcDatabases.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aDatabaseID := Longint(Database);
|
|
end;
|
|
end;
|
|
{----------}
|
|
destructor TFFProxyClient.Destroy;
|
|
{Begin !!.03}
|
|
//var
|
|
// Idx : Longint;
|
|
begin
|
|
{Destroy managed objects}
|
|
pcMsgQueue.Free;
|
|
pcMsgQueue := nil;
|
|
pcSessions.Free;
|
|
pcSessions := nil;
|
|
pcDatabases.Free;
|
|
pcDatabases := nil;
|
|
// with pcDatabases.BeginWrite do
|
|
// try
|
|
// for Idx := 0 to Pred(Count) do
|
|
// TFFProxyDatabase(Items[Idx]).Free;
|
|
// finally
|
|
// EndWrite;
|
|
// end;
|
|
|
|
// with pcSessions.BeginWrite do
|
|
// try
|
|
// for Idx := 0 to Pred(Count) do
|
|
// TFFProxySession(Items[Idx]).Free;
|
|
// finally
|
|
// EndWrite;
|
|
// end;
|
|
|
|
{Tell the server that we are disconnecting.}
|
|
if not ForceClosed then
|
|
if SrClientID > 0 then
|
|
pcTransport.TerminateConnection(SrClientID, Timeout);
|
|
|
|
// {Destroy internal classes}
|
|
// pcMsgQueue.Free;
|
|
// pcMsgQueue := nil;
|
|
// pcSessions.Free;
|
|
// pcSessions := nil;
|
|
// pcDatabases.Free;
|
|
// pcDatabases := nil;
|
|
{End !!.03}
|
|
|
|
{Re-Initialize internals for completeness}
|
|
pcCurrentSession := nil;
|
|
pcTransport := nil;
|
|
pcCallbackMethod := nil;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
{----------}
|
|
function TffProxyClient.IsReadOnly : Boolean;
|
|
var
|
|
Reply : PffnmServerIsReadOnlyRpy;
|
|
ReplyLen : Longint;
|
|
ErrorCode : TffResult;
|
|
begin
|
|
Reply := nil;
|
|
ErrorCode := ProcessRequest(ffnmServerIsReadOnly,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(ErrorCode) then
|
|
Result := Reply^.IsReadOnly
|
|
else
|
|
Result := False;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetServerDateTime(var aDateTime : TDateTime
|
|
) : TffResult;
|
|
var
|
|
Reply : PffnmGetServerDateTimeRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Just in case }
|
|
aDateTime := Now;
|
|
|
|
{ We have no data to send }
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmGetServerDateTime,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aDateTime := Reply^.ServerNow;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------} {begin !!.07}
|
|
function TFFProxyClient.GetServerSystemTime(var aSystemTime : TSystemTime) : TffResult;
|
|
var
|
|
Reply : PffnmGetServerSystemTimeRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Just in case }
|
|
GetSystemTime(aSystemTime);
|
|
|
|
{ We have no data to send }
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmGetServerSystemTime,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aSystemTime := Reply^.ServerNow;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetServerGUID(var aGUID : TGUID) : TffResult;
|
|
var
|
|
Reply : PffnmGetServerGUIDRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Just in case }
|
|
CoCreateGuid(aGUID);
|
|
|
|
{ We have no data to send }
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmGetServerGUID,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aGUID := Reply^.GUID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetServerID(var aUniqueID : TGUID) : TffResult;
|
|
var
|
|
Reply : PffnmGetServerIDRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ We have no data to send }
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmGetServerID,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aUniqueID := Reply^.UniqueID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetServerStatistics(var Stats : TffServerStatistics) : TffResult;
|
|
var
|
|
Reply : PffnmServerStatisticsRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ We have no data to send }
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmServerStatistics,
|
|
Timeout,
|
|
nil,
|
|
0,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
Stats := Reply^.Stats;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetCommandHandlerStatistics(const CmdHandlerIdx : Integer;
|
|
var Stats : TffCommandHandlerStatistics) : TffResult;
|
|
var
|
|
Request : TffnmCmdHandlerStatisticsReq;
|
|
Reply : PffnmCmdHandlerStatisticsRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initiailize Request }
|
|
Request.CmdHandlerIdx := CmdHandlerIdx;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmCmdHandlerStatistics,
|
|
pcTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
Stats := Reply^.Stats;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.GetTransportStatistics(const CmdHandlerIdx : Integer;
|
|
const Transportidx : Integer;
|
|
var Stats : TffTransportStatistics) : TffResult;
|
|
var
|
|
Request : TffnmTransportStatisticsReq;
|
|
Reply : PffnmTransportStatisticsRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initiailize Request }
|
|
Request.CmdHandlerIdx := CmdHandlerIdx;
|
|
Request.TransportIdx := Transportidx;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmTransportStatistics,
|
|
pcTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
Stats := Reply^.Stats;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------} {end !!.07}
|
|
function TFFProxyClient.ProcessRequest(aMsgID : longInt;
|
|
aTimeout : longInt;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : longInt;
|
|
aRequestDataType : TffNetMsgDataType;
|
|
var aReply : Pointer;
|
|
var aReplyLen : longInt;
|
|
aReplyType : TffNetMsgDataType
|
|
) : TffResult;
|
|
var
|
|
ReplyAsStream : TStream absolute aReply;
|
|
ReplyMsg : PffDataMessage;
|
|
begin
|
|
if ForceClosed then begin
|
|
Result := DBIERR_NONE;
|
|
aReply := nil;
|
|
aReplyLen := 0;
|
|
Exit;
|
|
end;
|
|
|
|
Result := DBIERR_NA;
|
|
{A Respose from the server is expected. This call will not return until
|
|
the complete reply has been sent to the transport, and the Client
|
|
callback method has been called.}
|
|
|
|
{ Use the ProxessRequest method to submit a request that is routed to the
|
|
transport. This method does the following:
|
|
|
|
1. Calls TffBaseTransport.Request with transportID = 0 and cookie
|
|
equal to Pointer(Self). At this point, the calling thread is
|
|
blocked until a reply is received from the server or a timeout
|
|
occurs.
|
|
2. When the calling thread returns to this method, the reply has
|
|
been received and placed in the message queue by the
|
|
ProxyClientCallback procedure.
|
|
3. Get the first message off the queue and verify it is what we
|
|
expected.
|
|
4. Put the message into the Reply variables and exit.
|
|
}
|
|
|
|
{ Is our reply already in the queue (e.g., came back as part
|
|
of a multi-part message? Assumption: We can get rid of any
|
|
replies that don't match the message we are requesting. }
|
|
ReplyMsg := pcMsgQueue.SoftPop;
|
|
while Assigned(ReplyMsg) and (ReplyMsg^.dmMsg <> aMsgID) do begin
|
|
FFFreeMem(ReplyMsg^.dmData, ReplyMsg^.dmDataLen);
|
|
FFFreeMem(ReplyMsg, SizeOf(TFFDataMessage));
|
|
ReplyMsg := pcMsgQueue.SoftPop;
|
|
end;
|
|
|
|
if not Assigned(ReplyMsg) then begin
|
|
|
|
pcTransport.Request(0, {For use by future protocols.}
|
|
SrClientID,
|
|
aMsgID,
|
|
aTimeout,
|
|
aRequestData,
|
|
aRequestDataLen,
|
|
pcCallbackMethod,
|
|
Longint(Self));
|
|
|
|
{Process the reply from the server. Get the reply message off the queue
|
|
and verify that is what we expected}
|
|
Assert(pcMsgQueue.Count <= 1, 'Too many messages in the queue');
|
|
ReplyMsg := pcMsgQueue.SoftPop;
|
|
end;
|
|
|
|
if Assigned(ReplyMsg) then begin
|
|
if (ReplyMsg^.dmMsg <> aMsgID) then begin
|
|
Result := DBIERR_NOTSAMESESSION;
|
|
FFFreeMem(ReplyMsg^.dmData, ReplyMsg^.dmDataLen); {!!.03}
|
|
FFFreeMem(ReplyMsg, SizeOf(TFFDataMessage));
|
|
Exit;
|
|
end;
|
|
|
|
aReplyLen := ReplyMsg^.dmDataLen;
|
|
if aReplyType = nmdStream then begin
|
|
Assert(Assigned(ReplyAsStream));
|
|
ReplyAsStream.Position := 0;
|
|
if (aReplyLen > 0) then begin
|
|
ReplyAsStream.Write(ReplyMsg^.dmData^, aReplyLen);
|
|
FFFreeMem(ReplyMsg^.dmData, aReplyLen);
|
|
end;
|
|
end else
|
|
aReply := ReplyMsg^.dmData;
|
|
|
|
Result := ReplyMsg^.dmErrorCode;
|
|
|
|
{ Free the ReplyMsg, but leave RequestData alone.
|
|
The caller is responsible for releasing data.
|
|
We expect the caller to free the reply data.}
|
|
FFFreeMem(ReplyMsg, SizeOf(TFFDataMessage));
|
|
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.ProcessRequestNoReply(aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint
|
|
) : TffResult;
|
|
begin
|
|
if ForceClosed then begin
|
|
Result := DBIERR_NONE;
|
|
Exit;
|
|
end;
|
|
|
|
{No response from the server is expected, so this call will return as
|
|
soon as the request has been sent from the transport's queue}
|
|
|
|
pcTransport.Post(0, {For use by future protocols.}
|
|
SrClientID,
|
|
aMsgID,
|
|
aRequestData,
|
|
aRequestDataLen,
|
|
aTimeout,
|
|
ffrmNoReplyWaitUntilSent);
|
|
|
|
Result := DBIERR_NONE;
|
|
end;
|
|
{Begin !!.01}
|
|
{----------}
|
|
function TffProxyClient.RemoteRestart : TffResult;
|
|
begin
|
|
Result := ProcessRequestNoReply(ffnmServerRestart, Timeout, nil, 0);
|
|
end;
|
|
{----------}
|
|
function TffProxyClient.RemoteStart : TffResult;
|
|
begin
|
|
Result := ProcessRequestNoReply(ffnmServerStartup, Timeout, nil, 0);
|
|
end;
|
|
{----------}
|
|
function TffProxyClient.RemoteStop : TffResult;
|
|
begin
|
|
Result := ProcessRequestNoReply(ffnmServerStop, Timeout, nil, 0);
|
|
end;
|
|
{End !!.01}
|
|
{----------}
|
|
function TFFProxyClient.SessionAdd(var aSessionID : TffSessionID;
|
|
const aTimeout : Longint) : TffResult;
|
|
var
|
|
Session : TFFProxySession;
|
|
ListItem : TffIntListItem;
|
|
begin
|
|
Session := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Session := TFFProxySession.Create(Self, aTimeout);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Session) then begin
|
|
{Add Session to the internal list}
|
|
ListItem := TffIntListItem.Create(Longint(Session));
|
|
with pcSessions.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aSessionID := Longint(Session);
|
|
|
|
{Set the current session if it is nil}
|
|
if not Assigned(pcCurrentSession) then
|
|
pcCurrentSession := Session;
|
|
end;
|
|
end;
|
|
{Begin !!.06}
|
|
{----------}
|
|
function TFFProxyClient.SessionCloseInactiveTables : TffResult;
|
|
var
|
|
Request : TffnmSessionCloseInactiveTblReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initiailize Request }
|
|
Request.SessionID := pcCurrentSession.psSrSessionID;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmSessionCloseInactTbl,
|
|
pcTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{End !!.06}
|
|
{----------}
|
|
function TFFProxyClient.SessionCount : Longint;
|
|
begin
|
|
{Retun the number of sessions managed by the ProxyClient}
|
|
with pcSessions.BeginRead do
|
|
try
|
|
Result := Count;
|
|
finally
|
|
EndRead;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.SessionGetCurrent : TffProxySession;
|
|
begin
|
|
{Return the current session. This value will be nil if no sessions exist}
|
|
if Assigned(pcCurrentSession) then
|
|
Result := pcCurrentSession
|
|
else begin
|
|
if SessionCount > 0 then
|
|
{Return the first session in the list}
|
|
with pcSessions.BeginRead do
|
|
try
|
|
Result := TFFProxySession(Items[0]);
|
|
finally
|
|
EndRead;
|
|
end
|
|
else
|
|
{no sessions available}
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.SessionRemove(aSession : TFFProxySession) : TffResult;
|
|
begin
|
|
{Remove session from the internal list, and destroy.}
|
|
if not Assigned(aSession) then begin
|
|
{aSession parameter is invalid}
|
|
Result := DBIERR_INVALIDHNDL;
|
|
Exit;
|
|
end;
|
|
|
|
Result := DBIERR_NONE;
|
|
with pcSessions.BeginWrite do
|
|
try
|
|
Delete(aSession); {!!.01}
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aSession.Free;
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.SessionSetCurrent(aSession : TFFProxySession
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmSessionSetCurrentReq;
|
|
Reply : PffnmSessionSetCurrentReq;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{Set the Client's CurrentSession. This function will accept nil as a valid
|
|
option}
|
|
Request.SessionID := aSession.psSrSessionID;
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmSessionSetCurrent,
|
|
pcTimeOut,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
// Result := DBIERR_NONE;
|
|
pcCurrentSession := aSession;
|
|
end;
|
|
{----------}
|
|
function TffProxyClient.GetRebuildStatus(const aRebuildID : Longint;
|
|
var aIsPresent : Boolean;
|
|
var aStatus : TffRebuildStatus) : TffResult;
|
|
var
|
|
Request : TffnmGetRebuildStatusReq;
|
|
Reply : PffnmGetRebuildStatusRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initiailize Request }
|
|
Request.RebuildID := aRebuildID;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmGetRebuildStatus,
|
|
pcTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then begin
|
|
aIsPresent := Reply^.IsPresent;
|
|
aStatus := Reply^.Status;
|
|
end;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyClient.SetTimeout(const aTimeout : Longint) : TffResult;
|
|
var
|
|
Request : TffnmClientSetTimeoutReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
if pcTimeout = aTimeout then Exit;
|
|
|
|
pcTimeout := aTimeout;
|
|
{ Initialize request }
|
|
Request.Timeout := pcTimeout;
|
|
|
|
Reply := nil;
|
|
Result := ProcessRequest(ffnmClientSetTimeout,
|
|
pcTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
{ Calling ffnmClientSetTimeout only returns an error code to Result. }
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
|
|
{-TFFProxySession--------------------------------------------------------------}
|
|
constructor TFFProxySession.Create(aClient : TFFProxyClient;
|
|
aTimeout : Longint);
|
|
var
|
|
Request : TffnmSessionAddReq;
|
|
Reply : PffnmSessionAddRpy;
|
|
ReplyLen : Longint;
|
|
Result : TFFResult;
|
|
begin
|
|
inherited Create;
|
|
|
|
{Initalize the object}
|
|
psClient := aClient;
|
|
psSrSessionID := 0;
|
|
psTimeout := aTimeout;
|
|
|
|
{ Initiailize Request }
|
|
Request.Timeout := aTimeout;
|
|
|
|
{Create a session object, and add it to the list}
|
|
Reply := nil;
|
|
Result := psClient.ProcessRequest(ffnmSessionAdd,
|
|
psTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
{Make sure that result was valid before we continue}
|
|
Check(Result);
|
|
|
|
psSrSessionID := Reply^.SessionID;
|
|
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
destructor TFFProxySession.Destroy;
|
|
var
|
|
Request : TffnmSessionCloseReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
if SrSessionID > 0 then begin
|
|
{ Initiailize Request }
|
|
Request.SessionID := SrSessionID;
|
|
|
|
Reply := nil;
|
|
Client.ProcessRequest(ffnmSessionClose,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
|
|
psClient := nil;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
{----------}
|
|
function TFFProxySession.SetTimeout(aTimeout : Longint) : TffResult;
|
|
var
|
|
Request : TffnmSessionSetTimeoutReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
if psTimeout = aTimeout then Exit;
|
|
|
|
psTimeout := aTimeout;
|
|
|
|
{ Initiailize Request }
|
|
Request.SessionID := psSrSessionID;
|
|
Request.Timeout := psTimeout;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmSessionSetTimeout,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
|
|
|
|
{-TFFProxyDatabase-------------------------------------------------------------}
|
|
constructor TFFProxyDatabase.Create(aClient : TFFProxyClient;
|
|
aLocation : string;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
aIsAlias : Boolean);
|
|
var
|
|
RequestAlias : TffnmDatabaseOpenReq;
|
|
RequestPath : TffnmDatabaseOpenNoAliasReq;
|
|
ReplyAlias : PffnmDatabaseOpenRpy;
|
|
ReplyPath : PffnmDatabaseOpenNoAliasRpy;
|
|
ReplyLen : Longint;
|
|
Result : TffResult;
|
|
begin
|
|
inherited Create;
|
|
|
|
pdInTrans := False;
|
|
pdSrDatabaseID := 0;
|
|
pdClient := aClient;
|
|
pdTimeout := aTimeout;
|
|
|
|
pdStmts := TffProxySQLStmtList.Create;
|
|
pdTables := TFFProxyCursorList.Create;
|
|
|
|
if aIsAlias then begin
|
|
{ Initiailize Request }
|
|
RequestAlias.Alias := aLocation;
|
|
RequestAlias.OpenMode := aOpenMode;
|
|
RequestAlias.ShareMode := aShareMode;
|
|
RequestAlias.Timeout := aTimeout;
|
|
|
|
ReplyAlias := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseOpen,
|
|
pdTimeout,
|
|
@RequestAlias,
|
|
SizeOf(RequestAlias),
|
|
nmdByteArray,
|
|
Pointer(ReplyAlias),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
Check(Result);
|
|
|
|
pdSrDatabaseID := ReplyAlias^.DatabaseID;
|
|
|
|
FFFreeMem(ReplyAlias, ReplyLen);
|
|
end else begin
|
|
{ Initiailize Request }
|
|
RequestPath.Path := aLocation;
|
|
RequestPath.OpenMode := aOpenMode;
|
|
RequestPath.ShareMode := aShareMode;
|
|
RequestPath.Timeout := aTimeout;
|
|
|
|
ReplyPath := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseOpenNoAlias,
|
|
pdTimeout,
|
|
@RequestPath,
|
|
SizeOf(RequestPath),
|
|
nmdByteArray,
|
|
Pointer(ReplyPath),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
Check(Result);
|
|
|
|
pdSrDatabaseID := ReplyPath^.DatabaseID;
|
|
|
|
FFFreeMem(ReplyPath, ReplyLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
destructor TFFProxyDatabase.Destroy;
|
|
var
|
|
// Idx : Longint; {!!.03}
|
|
Request : TffnmDatabaseCloseReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{Destroy dependent objects}
|
|
if InTrans then
|
|
TransactionRollback;
|
|
|
|
{Begin !!.03}
|
|
// with pdTables.BeginWrite do
|
|
// try
|
|
// for Idx := 0 to Pred(Count) do
|
|
// TFFProxyCursor(Items[Idx]).Free;
|
|
// finally
|
|
// EndWrite;
|
|
// end;
|
|
|
|
pdTables.Free;
|
|
pdTables := nil;
|
|
|
|
// with pdStmts.BeginWrite do
|
|
// try
|
|
// for Idx := 0 to Pred(Count) do
|
|
// TffProxySQLStmt(Items[Idx]).Free;
|
|
// finally
|
|
// EndWrite;
|
|
// end;
|
|
{End !!.03}
|
|
|
|
pdStmts.Free;
|
|
pdStmts := nil;
|
|
|
|
{Let the server know that we are leaving}
|
|
if SrDatabaseID > 0 then begin
|
|
{ Initiailize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
|
|
Reply := nil;
|
|
Client.ProcessRequest(ffnmDatabaseClose,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{Reset internals}
|
|
pdSrDatabaseID := 0;
|
|
pdClient := nil;
|
|
|
|
inherited;
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.GetDbFreeSpace(var aFreeSpace : Longint) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseGetFreeSpaceReq;
|
|
Reply : PffnmDatabaseGetFreeSpaceRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := pdSrDatabaseID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseGetFreeSpace,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aFreeSpace := Reply^.FreeSpace;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.QueryOpen(aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : longInt;
|
|
aStream : TStream;
|
|
var aFinalCursorID : TffCursorID) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
ListItem : TffIntListItem;
|
|
begin
|
|
Cursor := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Cursor := TFFProxyCursor.CreateSQL(Self, aCursorID, aOpenMode, aShareMode,
|
|
aTimeout, aStream);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Cursor) then begin
|
|
ListItem := TffIntListItem.Create(Longint(Cursor));
|
|
ListItem.MaintainLinks := False; {!!.02}
|
|
with pdTables.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aFinalCursorID := Longint(Cursor);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.SetTimeout(const aTimeout : Longint) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseSetTimeoutReq;
|
|
Reply : pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
if pdTimeout = aTimeout then Exit;
|
|
|
|
pdTimeout := aTimeout;
|
|
|
|
{ Initialize Request }
|
|
Request.DatabaseID := pdSrDatabaseID;
|
|
Request.Timeout := aTimeout;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseSetTimeout,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.SQLAlloc(const aTimeout : longInt;
|
|
var aStmtID : TffSqlStmtID) : TffResult;
|
|
var
|
|
ListItem : TffIntListItem;
|
|
Statement : TffProxySQLStmt;
|
|
begin
|
|
Statement := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Statement := TffProxySQLStmt.Create(Self, aTimeout);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Statement) then begin
|
|
ListItem := TffIntListItem.Create(Longint(Statement));
|
|
with pdStmts.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aStmtID := Longint(Statement);
|
|
end;
|
|
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.SQLExecDirect(aQueryText : PChar;
|
|
aOpenMode : TffOpenMode;
|
|
aTimeout : longInt;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
QueryLen : Longint;
|
|
ReplyLen : Longint;
|
|
Request : PffnmSQLExecDirectReq;
|
|
ReqLen : Longint;
|
|
SvrCursorID : TffCursorID;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
QueryLen := StrLen(aQueryText);
|
|
ReqLen := SizeOf(TffnmSQLExecDirectReq) - sizeOf(TffVarMsgField) + {!!.05}
|
|
QueryLen + 1; {!!.05}
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Prepare the request. }
|
|
Move(aQueryText^, Request^.Query, QueryLen);
|
|
Request^.DatabaseID := pdSrDatabaseID;
|
|
Request^.Timeout := aTimeout;
|
|
Request^.OpenMode := aOpenMode;
|
|
|
|
Result := pdClient.ProcessRequest(ffnmSQLExecDirect,
|
|
pdTimeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
{ Was the execution successful? }
|
|
if Result = DBIERR_NONE then begin
|
|
{ Yes. Get the cursorID from the stream & open a proxy cursor. }
|
|
aStream.Position := 0;
|
|
aStream.Read(SvrCursorID, sizeOf(SvrCursorID));
|
|
if SvrCursorID <> 0 then {!!.11}
|
|
Result := QueryOpen(SvrCursorID, aOpenMode, smShared, aTimeout,
|
|
aStream, aCursorID);
|
|
end;
|
|
|
|
{ Assumption: Upper levels are responsible for Stream contents. }
|
|
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableAddIndex(const aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexDesc : TffIndexDescriptor
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmAddIndexReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
if aCursorID > 0 then
|
|
Request.CursorID := TFFProxyCursor(aCursorID).SrCursorID
|
|
else
|
|
Request.CursorID := 0;
|
|
Request.TableName := aTableName;
|
|
Request.IndexDesc := aIndexDesc;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmAddIndex,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableBuild(aOverWrite : Boolean;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aDictionary : TffDataDictionary
|
|
) : TffResult;
|
|
var
|
|
Request : TMemoryStream;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request := TMemoryStream.Create;
|
|
try
|
|
Request.Write(pdSrDatabaseID, SizeOf(pdSRDatabaseID)); {!!.10}
|
|
Request.Write(aOverWrite, SizeOf(aOverWrite));
|
|
Request.Write(aTableName, SizeOf(aTableName));
|
|
aDictionary.WriteToStream(Request);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmBuildTable,
|
|
Timeout,
|
|
Request.Memory,
|
|
Request.Size,
|
|
nmdStream,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
Request.Free;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableClose(aCursor : TFFProxyCursor) : TffResult;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
|
|
with pdTables.BeginWrite do
|
|
try
|
|
Delete(aCursor); {!!.01}
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aCursor.Free;
|
|
aCursor := nil;
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableDelete(const aTableName : TffTableName
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmDeleteTableReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDeleteTable,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.TableDropIndex(aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffDictItemName;
|
|
aIndexID : longint) : TffResult;
|
|
var
|
|
Request : TffnmDropIndexReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
if aCursorID > 0 then
|
|
Request.CursorID := TFFProxyCursor(aCursorID).SrCursorID
|
|
else
|
|
Request.CursorID := aCursorID;
|
|
Request.TableName := aTableName;
|
|
Request.IndexName := aIndexName;
|
|
Request.IndexNumber := aIndexID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDropIndex,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.TableEmpty(aCursorID : TffCursorID;
|
|
const aTableName : TffTableName) : TffResult;
|
|
var
|
|
Request : TffnmEmptyTableReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
if aCursorID > 0 then
|
|
Request.CursorID := TFFProxyCursor(aCursorID).SrCursorID
|
|
else
|
|
Request.CursorID := aCursorID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmEmptyTable,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableGetDictionary(const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aStream : TStream
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmGetTableDictionaryReq;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := FFExtractFileName(aTableName);
|
|
|
|
aStream.Position := 0;
|
|
Result := Client.ProcessRequest(ffnmGetTableDictionary,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
end;
|
|
{----------}
|
|
function TffProxyDatabase.TableExists(const aTableName : TffTableName;
|
|
var aExists : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseTableExistsReq;
|
|
Reply : PffnmDatabaseTableExistsRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseTableExists,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aExists := Reply^.Exists;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableList(const aMask : TffFileNameExt;
|
|
aList : TList) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseTableListReq;
|
|
ReplyLen : Longint;
|
|
Stream : TStream;
|
|
TableDescr : PffTableDescriptor;
|
|
Count : Longint;
|
|
begin
|
|
Stream := TMemoryStream.Create;
|
|
try
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.Mask := aMask;
|
|
|
|
Result := Client.ProcessRequest(ffnmDatabaseTableList,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Stream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
if ResultOK(Result) then begin
|
|
{Build the list}
|
|
Stream.Position := 0;
|
|
aList.Clear;
|
|
|
|
for Count := 1 to (Stream.Size div SizeOf(TffTableDescriptor)) do begin
|
|
FFGetMem(TableDescr, SizeOf(TFFTableDescriptor));
|
|
Stream.Read(TableDescr^, SizeOf(TffTableDescriptor));
|
|
aList.Add(TableDescr);
|
|
end;
|
|
end;
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
function TffProxyDatabase.TableLockedExclusive(const aTableName : TffTableName;
|
|
var aLocked : Boolean
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmDatabaseTableLockedExclusiveReq;
|
|
Reply : PffnmDatabaseTableLockedExclusiveRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDatabaseTableLockedExclusive,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aLocked := Reply^.Locked;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableOpen(const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
ListItem : TffIntListItem;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Cursor := nil;
|
|
Result := DBIERR_NONE;
|
|
|
|
try
|
|
Cursor := TFFProxyCursor.Create(Self,
|
|
0,
|
|
aTableName,
|
|
aForServer,
|
|
aIndexName,
|
|
aIndexID,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
aStream);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or (E is EffDatabaseError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Cursor) then begin
|
|
ListItem := TffIntListItem.Create(Longint(Cursor));
|
|
ListItem.MaintainLinks := False; {!!.02}
|
|
with pdTables.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
aCursorID := Longint(Cursor);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TablePack(const aTableName : TffTableName;
|
|
var aRebuildID : Longint) : TffResult;
|
|
var
|
|
Request : TffnmPackTableReq;
|
|
Reply : PffnmPackTableRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
aRebuildID := -1;
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmPackTable,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
aRebuildID := Reply^.RebuildID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableRebuildIndex(const aTableName : TffTableName;
|
|
const aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
var aRebuildID : Longint
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmReindexTableReq;
|
|
Reply : PffnmReindexTableRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
aRebuildID := -1;
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
Request.IndexName := aIndexName;
|
|
Request.IndexNumber := aIndexID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmReindexTable,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aRebuildID := Reply^.RebuildID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableRename(const aOldName : TffName;
|
|
const aNewName : TffName) : TffResult;
|
|
var
|
|
Request : TffnmRenameTableReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.OldTableName := aOldName;
|
|
Request.NewTableName := aNewName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRenameTable,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TableRestructure(
|
|
const aTableName : TffTableName;
|
|
aDictionary : TffDataDictionary;
|
|
aFieldMap : TffStringList;
|
|
var aRebuildID : Longint
|
|
) : TffResult;
|
|
var
|
|
I : Longint;
|
|
NullByte : Byte;
|
|
Request : TMemoryStream;
|
|
Reply : PffnmRestructureTableRpy;
|
|
FieldMapEntry : TffShStr;
|
|
ReplyLen : Longint;
|
|
begin
|
|
NullByte := 0;
|
|
aRebuildID := -1;
|
|
|
|
{ Initialize Request }
|
|
Request := TMemoryStream.Create;
|
|
try
|
|
Request.Write(SrDatabaseID, SizeOf(LongInt));
|
|
Request.Write(aTableName, SizeOf(aTableName));
|
|
aDictionary.WriteToStream(Request);
|
|
if Assigned(aFieldMap) then
|
|
for I := 0 to aFieldMap.Count - 1 do begin
|
|
FieldMapEntry := aFieldMap[I];
|
|
Request.Write(FieldMapEntry, Length(FieldMapEntry) + 1);
|
|
end;
|
|
Request.Write(NullByte, SizeOf(NullByte));
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRestructureTable,
|
|
Timeout,
|
|
Request.Memory,
|
|
Request.Size,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
aRebuildID := Reply^.RebuildID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
finally
|
|
Request.Free;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TransactionCommit : TffResult;
|
|
var
|
|
Request : TffnmEndTransactionReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.ToBeCommitted := True;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmEndTransaction,
|
|
pdTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TransactionRollback : TffResult;
|
|
var
|
|
Request : TffnmEndTransactionReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.ToBeCommitted := False;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmEndTransaction,
|
|
pdTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyDatabase.TransactionStart(aFailSafe : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmStartTransactionReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DatabaseID := SrDatabaseID;
|
|
Request.FailSafe := aFailSafe;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmStartTransaction,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
Check(Result);
|
|
end;
|
|
|
|
//soner FlashBufferHack
|
|
type
|
|
TBinaryObjectWriterHack = class(TBinaryObjectWriter)
|
|
public
|
|
//procedure FlushBuffer;
|
|
end;
|
|
//end soner FlashBufferHack
|
|
{Start !!.10}
|
|
{----------}
|
|
function TFFProxyDatabase.TransactionStartWith(const aFailSafe : Boolean;
|
|
const aCursorIDs : TffPointerList
|
|
) : TffResult;
|
|
var
|
|
Reply : Pointer;
|
|
Inx,
|
|
aCount,
|
|
ReplyLen : Longint;
|
|
Request : TMemoryStream;
|
|
Writer : TWriter;
|
|
begin
|
|
{ Initialize Request }
|
|
Request := TMemoryStream.Create;
|
|
Writer := TWriter.Create(Request, 4096);
|
|
try
|
|
Writer.WriteInteger(pdSrDatabaseID);
|
|
Writer.WriteBoolean(aFailSafe);
|
|
aCount := aCursorIDs.Count;
|
|
Writer.WriteInteger(aCount);
|
|
for Inx := 0 to Pred(aCount) do
|
|
{ Get the cursorID of the proxy cursor. }
|
|
Writer.WriteInteger(TffProxyCursor(aCursorIDs[Inx]).SrCursorID);
|
|
{$ifdef fpc}
|
|
TBinaryObjectWriterHack(Writer.Driver).FlushBuffer; //soner
|
|
{$else}
|
|
Writer.FlushBuffer;
|
|
{$endif}
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmStartTransactionWith,
|
|
Timeout,
|
|
Request.Memory,
|
|
Request.Size,
|
|
nmdStream,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
finally
|
|
Writer.Free;
|
|
Request.Free;
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
// Check(Result); {Deleted !!.11}
|
|
end;
|
|
{End !!.10}
|
|
{------------------------------------------------------------------------------}
|
|
|
|
|
|
|
|
{-TFFProxyCursor---------------------------------------------------------------}
|
|
function TFFProxyCursor.BlobCreate(var aBlobNr : TFFInt64) : TffResult;
|
|
var
|
|
Request : TffnmCreateBLOBReq;
|
|
Reply : PffnmCreateBLOBRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCreateBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
aBlobNr := Reply^.BLOBNr;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.BLOBDelete(aBlobNr : TFFInt64) : TffResult;
|
|
var
|
|
Request : TffnmDeleteBLOBReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBlobNr;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmDeleteBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.BLOBFree(aBlobNr : TffInt64;
|
|
aReadOnly : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmFreeBLOBReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBLOBNr;
|
|
Request.ReadOnly := aReadOnly;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmFreeBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.BLOBGetLength(aBlobNr : TffInt64;
|
|
var aLength : Longint) : TffResult;
|
|
var
|
|
Request : TffnmGetBLOBLengthReq;
|
|
Reply : PffnmGetBLOBLengthRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBLOBNr;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmGetBLOBLength,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aLength := Reply^.BLOBLength;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{Begin !!.03}
|
|
{----------}
|
|
function TffProxyCursor.BLOBListSegments(aBLOBNr : TffInt64;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Request : TffnmListBLOBSegmentsReq;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBLOBNr;
|
|
Result := Client.ProcessRequest(ffnmListBLOBSegments,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
if ResultOK(Result) then
|
|
aStream.Position := 0;
|
|
end;
|
|
{End !!.03}
|
|
{----------}
|
|
function TFFProxyCursor.BLOBRead(aBlobNr : TffInt64;
|
|
aOffset : TffWord32; {!!.06}
|
|
aLen : TffWord32; {!!.06}
|
|
var aBLOB;
|
|
var aBytesRead : TffWord32) {!!.06}
|
|
: TffResult;
|
|
var
|
|
Request : TffnmReadBLOBReq;
|
|
Reply : PffnmReadBLOBRpy;
|
|
ReplyLen : longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBLOBNr;
|
|
Request.Offset := aOffset;
|
|
Request.Len := aLen;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmReadBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then begin
|
|
aBytesRead := Reply^.BytesRead;
|
|
Move(Reply^.BLOB, aBLOB, aBytesRead);
|
|
end;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.BLOBTruncate(aBlobNr : TffInt64;
|
|
aBLOBLength : Longint) : TffResult;
|
|
var
|
|
Request : TffnmTruncateBLOBReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BLOBNr := aBLOBNr;
|
|
Request.BLOBLength := aBLOBLength;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmTruncateBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.BLOBWrite(aBlobNr : TffInt64;
|
|
aOffset : Longint;
|
|
aLen : Longint;
|
|
var aBLOB) : TffResult;
|
|
var
|
|
Request : PffnmWriteBLOBReq;
|
|
ReqLen : longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(TffnmWriteBLOBReq) - 2 + aLen;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.BLOBNr := aBLOBNr;
|
|
Request^.Offset := aOffSet;
|
|
Request^.Len := aLen;
|
|
Move(aBLOB, Request^.BLOB, aLen);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmWriteBLOB,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.CompareBookmarks(aBookmark1 : PffByteArray;
|
|
aBookmark2 : PffByteArray;
|
|
var aCompResult : Longint) : TffResult;
|
|
var
|
|
Request : PffnmCursorCompareBMsReq;
|
|
ReqLen : Longint;
|
|
Reply : PffnmCursorCompareBMsRpy;
|
|
pBM2 : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(TffnmCursorCompareBMsReq) - 4 + (2 * BookmarkSize);
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.BookmarkSize := BookmarkSize;
|
|
Move(aBookMark1^, Request^.Bookmark1, BookmarkSize);
|
|
pBM2 := PffByteArray(PAnsiChar(@Request^.BookMark1) + BookmarkSize);
|
|
Move(aBookMark2^, pBM2^, BookmarkSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorCompareBMs,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aCompResult := Reply^.CompareResult;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
constructor TFFProxyCursor.Create(aDatabase : TFFProxyDatabase;
|
|
aCursorID : TffCursorID;
|
|
aTableName : string;
|
|
aForServer : Boolean;
|
|
aIndexName : string;
|
|
aIndexID : Longint;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : Longint;
|
|
aStream : TStream);
|
|
var
|
|
Request : TffnmOpenTableReq;
|
|
ReplyLen : Longint;
|
|
Result : TffResult;
|
|
|
|
begin
|
|
inherited Create;
|
|
|
|
prClient := aDatabase.Client;
|
|
prDatabase := aDatabase;
|
|
prSrCursorID := aCursorID;
|
|
prTableName := aTableName;
|
|
prForServer := aForServer;
|
|
prDictionary := TffDataDictionary.Create(4096);
|
|
prIndexName := aIndexName;
|
|
prIndexID := aIndexID;
|
|
prIsSQLCursor := false;
|
|
prShareMode := aShareMode;
|
|
prPhyRecSize := 0;
|
|
prTimeout := aTimeout;
|
|
|
|
if prSrCursorID <> 0 then Exit; {CursorClone operation, nothing more to do}
|
|
|
|
Assert(Assigned(aStream));
|
|
|
|
{ Initialize Request }
|
|
Request.DatabaseID := Database.SrDatabaseID;
|
|
Request.TableName := FFExtractTableName(aTableName);
|
|
Request.IndexName := aIndexName;
|
|
Request.IndexNumber := aIndexID;
|
|
Request.OpenMode := aOpenMode;
|
|
Request.ShareMode := aShareMode;
|
|
Request.Timeout := prTimeout;
|
|
|
|
Result := Client.ProcessRequest(ffnmOpenTable,
|
|
prTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
Check(Result);
|
|
|
|
aStream.Position := 0;
|
|
aStream.Read(prSrCursorID, SizeOf(prSrCursorID));
|
|
|
|
{save the data dictionary for this table as well}
|
|
|
|
Dictionary.ReadFromStream(aStream);
|
|
aStream.Read(prIndexID, SizeOf(prIndexID));
|
|
prIndexName := prDictionary.IndexName[prIndexID];
|
|
prPhyRecSize := prDictionary.RecordLength;
|
|
end;
|
|
{----------}
|
|
constructor TffProxyCursor.CreateSQL(aDatabase : TffProxyDatabase;
|
|
aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
aTimeout : longInt;
|
|
aStream : TStream);
|
|
begin
|
|
inherited Create;
|
|
|
|
Assert(Assigned(aStream));
|
|
|
|
prClient := aDatabase.Client;
|
|
prDatabase := aDatabase;
|
|
prTableName := '';
|
|
prForServer := false;
|
|
prDictionary := TffDataDictionary.Create(ffcl_64k);
|
|
prIsSQLCursor := True;
|
|
prShareMode := aShareMode;
|
|
prTimeout := aTimeout;
|
|
|
|
aStream.Position := 0;
|
|
aStream.Read(prSrCursorID, SizeOf(prSrCursorID));
|
|
|
|
{ Save the data dictionary for this table. }
|
|
|
|
Dictionary.ReadFromStream(aStream);
|
|
// aStream.Read(prIndexID, SizeOf(prIndexID)); {Deleted !!.10}
|
|
prIndexID := 0; {!!.10}
|
|
prIndexName := prDictionary.IndexName[0]; {!!.10}
|
|
prPhyRecSize := prDictionary.RecordLength;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.CursorClone(aOpenMode : TFFOpenMode;
|
|
var aNewCursorID : TFFCursorID) : TffResult;
|
|
var
|
|
Request : TffnmCursorCloneReq;
|
|
Reply : PffnmCursorCloneRpy;
|
|
ReplyLen : Longint;
|
|
NewCursor : TffProxyCursor;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.OpenMode := aOpenMode;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorClone,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then begin
|
|
{Create a new proxy cursor with the appropriate information}
|
|
NewCursor := TffProxyCursor.Create(prDatabase,
|
|
Reply^.CursorID,
|
|
''{tableName},
|
|
False, {forserver}
|
|
prIndexName,
|
|
prIndexID,
|
|
aOpenMode,
|
|
smShared, {share mode}
|
|
prTimeout,
|
|
nil);
|
|
NewCursor.prDictionary.Assign(prDictionary);
|
|
NewCursor.prIndexName := prIndexName;
|
|
NewCursor.prPhyRecSize := NewCursor.prDictionary.RecordLength;
|
|
aNewCursorID := Longint(NewCursor);
|
|
end;
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
destructor TFFProxyCursor.Destroy;
|
|
var
|
|
Request : TffnmCursorCloseReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
if SrCursorID > 0 then begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Client.ProcessRequest(ffnmCursorClose,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
|
|
prSrCursorID := 0;
|
|
prDictionary.Free;
|
|
prDictionary := nil;
|
|
prDatabase := nil;
|
|
prClient := nil;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.FileBLOBAdd(const aFileName : TffFullFileName;
|
|
var aBlobNr : TffInt64) : TffResult;
|
|
var
|
|
Request : TffnmAddFileBLOBReq;
|
|
Reply : PffnmAddFileBLOBRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.FileName := aFileName;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmAddFileBLOB,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
aBlobNr := Reply^.BLOBNr;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{Begin !!.02}
|
|
{----------}
|
|
function TffProxyCursor.CopyRecords(aSrcCursor : TffProxyCursor;
|
|
aCopyBLOBs : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmCursorCopyRecordsReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
|
|
{ Initialize Request }
|
|
Request.SrcCursorID := aSrcCursor.SrCursorID;
|
|
Request.DestCursorID := SrCursorID;
|
|
Request.CopyBLOBs := aCopyBLOBs;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorCopyRecords,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{End !!.02}
|
|
{Begin !!.06}
|
|
{----------}
|
|
function TffProxyCursor.DeleteRecords : TffResult;
|
|
var
|
|
Request : TffnmCursorDeleteRecordsReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorDeleteRecords,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{End !!.06}
|
|
{----------}
|
|
function TFFProxyCursor.GetBookmark(aBookmark : PffByteArray) : TffResult;
|
|
var
|
|
Request : TffnmCursorGetBookMarkReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.BookMarkSize := BookMarkSize;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorGetBookMark,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
Move(Reply^, aBookmark^, BookmarkSize); {!!.05}
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.GetBookmarkSize(var aSize : Longint) : TffResult;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
if prIsSQLCursor then
|
|
aSize := ffcl_FixedBookmarkSize
|
|
else
|
|
aSize := ffcl_FixedBookmarkSize + Dictionary.IndexKeyLength[IndexID];
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.prGetBookmarkSize : Longint;
|
|
begin
|
|
GetBookmarkSize(Result);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordDelete(aData : PffByteArray) : TffResult;
|
|
var
|
|
Request : TffnmRecordDeleteReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
if aData = nil then
|
|
Request.RecLen := 0
|
|
else
|
|
Request.RecLen := PhysicalRecordSize;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordDelete,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ((ResultOK(Result)) and {!!.06}
|
|
(Assigned(aData))) then {!!.06}
|
|
Move(Reply^, aData^, ReplyLen);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyCursor.RecordDeleteBatch(aBMCount : Longint;
|
|
aBMLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray
|
|
) : TffResult;
|
|
var
|
|
Request : PffnmRecordDeleteBatchReq;
|
|
MaxRecs : LongInt;
|
|
ReqLen : LongInt;
|
|
iErr : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
MaxRecs := 65500 div aBMLen;
|
|
if aBMCount > MaxRecs then begin
|
|
Result := DBIERR_ROWFETCHLIMIT;
|
|
Exit;
|
|
end;
|
|
ReqLen := SizeOf(Request^) - 2 + (aBMLen * aBMCount);
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.BMLen := aBMLen;
|
|
Request^.BMCount := aBMCount;
|
|
Move(aData^, Request^.BMArray, aBMCount * aBMLen);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordDeleteBatch,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then begin
|
|
Move(Reply^, aErrors^, ReplyLen);
|
|
for iErr := 0 to Pred(aBMCount) do
|
|
if aErrors^[iErr] <> DBIERR_NONE then begin
|
|
Result := aErrors^[iErr];
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordExtractKey(aData : PffByteArray;
|
|
aKey : PffByteArray) : TffResult;
|
|
var
|
|
Request : PffnmRecordExtractKeyReq;
|
|
ReqLen : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(TffnmRecordExtractKeyReq) - 2 + PhysicalRecordSize;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request}
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.KeyLen := Dictionary.IndexKeyLength[IndexID];
|
|
if aData = nil then
|
|
Request^.ForCurrentRecord := True
|
|
else begin
|
|
Move(aData^, Request^.Data, PhysicalRecordSize);
|
|
Request^.ForCurrentRecord := False;
|
|
end;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordExtractKey,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ((ResultOK(Result)) and {!!.06}
|
|
(Assigned(aKey))) then {!!.06}
|
|
Move(Reply^, aKey^, ReplyLen);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen); {!!.06}
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordGet(aLockType : TffLockType;
|
|
aData : PffByteArray)
|
|
: TffResult;
|
|
var
|
|
Request : TffnmRecordGetReq;
|
|
Reply : Pointer;
|
|
RpyLen : TffMemSize;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
Request.RecLen := PhysicalRecordSize; {server needs it no matter what}
|
|
Request.BookMarkSize := BookMarkSize;
|
|
if (aData = nil) then
|
|
RpyLen := 0
|
|
else
|
|
RpyLen := Request.RecLen;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordGet,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
RpyLen,
|
|
nmdByteArray);
|
|
if ((Assigned(Reply)) and {!!.06}
|
|
(Assigned(aData))) then begin {!!.06}
|
|
Move(Reply^, aData^, RpyLen);
|
|
FFFreeMem(Reply, RpyLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordGetBatch(aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
var aRecRead : Longint;
|
|
aData : PffByteArray;
|
|
var aError : TffResult) : TffResult;
|
|
var
|
|
Request : TffnmRecordGetBatchReq;
|
|
Reply : PffnmRecordGetBatchRpy;
|
|
ReplyLen : LongInt;
|
|
begin
|
|
aRecRead := 0;
|
|
ReplyLen := SizeOf(Reply^) - 2 + (aRecLen * aRecCount);
|
|
Request.CursorID := SrCursorID;
|
|
Request.RecLen := aRecLen;
|
|
Request.RecCount := aRecCount;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordGetBatch,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then begin
|
|
aRecRead := Reply^.RecCount;
|
|
Move(Reply^.RecArray, aData^, aRecRead * aRecLen);
|
|
aError := Reply^.Error;
|
|
end;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordGetForKey(aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray;
|
|
aData : PffByteArray;
|
|
aFirstCall : Boolean) : TffResult;
|
|
var
|
|
Request : PffnmRecordGetForKeyReq;
|
|
ReqLen : longint;
|
|
Reply : Pointer;
|
|
RpyLen : longint;
|
|
DataLen : Longint;
|
|
DictRecLen : Longint;
|
|
begin
|
|
DictRecLen := PhysicalRecordSize;
|
|
if aDirectKey then
|
|
DataLen := Dictionary.IndexKeyLength[IndexID]
|
|
else
|
|
DataLen := DictRecLen;
|
|
ReqLen := SizeOf(TffnmRecordGetForKeyReq) - 2 + DataLen;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
if (aData = nil) then
|
|
RpyLen := 0
|
|
else
|
|
RpyLen := DictRecLen;
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.BookMarkSize := BookMarkSize;
|
|
Request^.DirectKey := aDirectKey;
|
|
Request^.FieldCount := aFieldCount;
|
|
Request^.PartialLen := aPartialLen;
|
|
Request^.RecLen := DictRecLen;
|
|
Request^.KeyDataLen := DataLen;
|
|
Move(aKeyData^, Request^.KeyData, DataLen);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordGetForKey,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
RpyLen,
|
|
nmdByteArray);
|
|
|
|
if ((Assigned(Reply)) and {!!.06}
|
|
(Assigned(aData))) then begin {!!.06}
|
|
Move(Reply^, aData^, RpyLen);
|
|
FFFreeMem(Reply, RpyLen);
|
|
end;
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordGetNext(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
var
|
|
Request : TffnmRecordGetNextReq;
|
|
ReplyLen : Longint;
|
|
Reply : Pointer;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
if (aData <> nil) then begin
|
|
Request.RecLen := PhysicalRecordSize;
|
|
Request.BookMarkSize := BookMarkSize;
|
|
end else begin
|
|
Request.RecLen := 0;
|
|
Request.BookMarkSize := 0;
|
|
end;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordGetNext,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then begin
|
|
Move(Reply^, aData^, ReplyLen);
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordGetPrior(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
var
|
|
Request : TffnmRecordGetPrevReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
if (aData <> nil) then begin
|
|
Request.RecLen := PhysicalRecordSize;
|
|
Request.BookMarkSize := BookMarkSize;
|
|
end
|
|
else begin
|
|
Request.RecLen := 0;
|
|
Request.BookMarkSize := 0;
|
|
end;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordGetPrev,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then begin
|
|
Move(Reply^, aData^, ReplyLen);
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordInsert(aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
var
|
|
Request : PffnmRecordInsertReq;
|
|
ReqLen : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(Request^) - 2 + PhysicalRecordSize;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.LockType := aLockType;
|
|
Request^.RecLen := PhysicalRecordSize;
|
|
Request^.BookMarkSize := BookMarkSize;
|
|
Move(aData^, Request^.Data, PhysicalRecordSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordInsert,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordInsertBatch(aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray
|
|
) : TffResult;
|
|
var
|
|
Request : PffnmRecordInsertBatchReq;
|
|
MaxRecs : LongInt;
|
|
ReqLen : LongInt;
|
|
iErr : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
MaxRecs := 65500 div aRecLen;
|
|
if aRecCount > MaxRecs then begin
|
|
Result := DBIERR_ROWFETCHLIMIT;
|
|
Exit;
|
|
end;
|
|
ReqLen := SizeOf(Request^) - 2 + (aRecLen * aRecCount);
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.RecLen := aRecLen;
|
|
Request^.RecCount := aRecCount;
|
|
Move(aData^, Request^.RecArray, aRecCount * aRecLen);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordInsertBatch,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then begin
|
|
Move(Reply^, aErrors^, ReplyLen);
|
|
for iErr := 0 to Pred(aRecCount) do
|
|
if aErrors^[iErr] <> DBIERR_NONE then begin
|
|
Result := aErrors^[iErr];
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TffProxyCursor.RecordIsLocked(aLockType : TffLockType;
|
|
var aIsLocked : boolean) : TffResult;
|
|
var
|
|
Request : TffnmRecordIsLockedReq;
|
|
Reply : PffnmRecordIsLockedRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordIsLocked,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aIsLocked := Reply^.IsLocked;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordModify(aData : PffByteArray;
|
|
aRelLock : Boolean) : TffResult;
|
|
var
|
|
Request : PffnmRecordModifyReq;
|
|
ReqLen : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(Request^) - 2 + PhysicalRecordSize;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.RelLock := aRelLock;
|
|
Request^.RecLen := PhysicalRecordSize;
|
|
Request^.BookMarkSize := BookMarkSize;
|
|
Move(aData^, Request^.Data, PhysicalRecordSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordModify,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.RecordRelLock(aAllLocks : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmRecordRelLockReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.AllLocks := aAllLocks;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRecordRelLock,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TffProxyCursor.TableGetAutoInc(var aValue : TffWord32) : TffResult;
|
|
var
|
|
Request : TffnmGetTableAutoIncValueReq;
|
|
Reply : PffnmGetTableAutoIncValueRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmGetTableAutoIncValue,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aValue := Reply^.AutoIncValue;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{Begin !!.03}
|
|
{----------}
|
|
function TffProxyCursor.ListBLOBFreeSpace(const aInMemory : Boolean;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Request : TffnmGetBLOBFreeSpaceReq;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Request.CursorID := SrCursorID;
|
|
Request.InMemory := aInMemory;
|
|
Result := Client.ProcessRequest(ffnmListBLOBFreeSpace,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
if ResultOK(Result) then
|
|
aStream.Position := 0;
|
|
end;
|
|
{End !!.03}
|
|
{----------}
|
|
function TffProxyCursor.OverrideFilter(aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult;
|
|
var
|
|
ReqSize : Longint;
|
|
Request : PffnmCursorOverrideFilterReq;
|
|
ExprTree : CANExpr;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
|
|
if not Assigned(aExpression) then begin
|
|
aExpression := @ExprTree;
|
|
FillChar(ExprTree, SizeOf(ExprTree), 0);
|
|
ExprTree.iVer := CANEXPRVERSION;
|
|
ExprTree.iTotalSize := SizeOf(ExprTree);
|
|
end;
|
|
|
|
ReqSize := (SizeOf(Request^) - 2 + aExpression^.iTotalSize);
|
|
|
|
FFGetMem(Request, ReqSize);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.Timeout := aTimeout;
|
|
|
|
Move(aExpression^, Request^.ExprTree, aExpression^.iTotalSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorOverrideFilter,
|
|
Timeout,
|
|
Pointer(Request),
|
|
ReqSize,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqSize);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.ResetRange : TffResult;
|
|
var
|
|
Request : TffnmCursorResetRangeReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorResetRange,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
end;
|
|
{----------}
|
|
function TffProxyCursor.RestoreFilter : TffResult;
|
|
var
|
|
Request : TffnmCursorRestoreFilterReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorRestoreFilter,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetFilter(aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult;
|
|
var
|
|
ReqSize : Longint;
|
|
Request : PffnmCursorSetFilterReq;
|
|
ExprTree : CANExpr;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
if not Assigned(aExpression) then begin
|
|
aExpression := @ExprTree;
|
|
FillChar(ExprTree, SizeOf(ExprTree), 0);
|
|
ExprTree.iVer := CANEXPRVERSION;
|
|
ExprTree.iTotalSize := SizeOf(ExprTree);
|
|
end;
|
|
|
|
ReqSize := (SizeOf(Request^) - 2 + aExpression^.iTotalSize);
|
|
|
|
FFGetMem(Request, ReqSize);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.Timeout := aTimeout;
|
|
|
|
Move(aExpression^, Request^.ExprTree, aExpression^.iTotalSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetFilter,
|
|
Timeout,
|
|
Pointer(Request),
|
|
ReqSize,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqSize);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetRange(aDirectKey : Boolean;
|
|
aFieldCount1 : Longint;
|
|
aPartialLen1 : Longint;
|
|
aKeyData1 : PffByteArray;
|
|
aKeyIncl1 : Boolean;
|
|
aFieldCount2 : Longint;
|
|
aPartialLen2 : Longint;
|
|
aKeyData2 : PffByteArray;
|
|
aKeyIncl2 : Boolean) : TffResult;
|
|
var
|
|
Request : PffnmCursorSetRangeReq;
|
|
ReqLen : Longint;
|
|
KeyLen1 : Longint;
|
|
KeyLen2 : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
ReqKeyData2 : pointer;
|
|
begin
|
|
{calculate sizes}
|
|
if aKeyData1 = nil then
|
|
KeyLen1 := 0
|
|
else if aDirectKey then
|
|
KeyLen1 := Dictionary.IndexKeyLength[ IndexID ]
|
|
else
|
|
KeyLen1 := PhysicalRecordSize;
|
|
if aKeyData2 = nil then
|
|
KeyLen2 := 0
|
|
else if aDirectKey then
|
|
KeyLen2 := Dictionary.IndexKeyLength[ IndexID ]
|
|
else
|
|
KeyLen2 := PhysicalRecordSize;
|
|
|
|
{now, we know how large the Request is}
|
|
ReqLen := SizeOf(Request^) - 4 + KeyLen1 + KeyLen2;
|
|
|
|
{allocate and clear it}
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.DirectKey := aDirectKey;
|
|
Request^.FieldCount1 := aFieldCount1;
|
|
Request^.PartialLen1 := aPartialLen1;
|
|
Request^.KeyLen1 := KeyLen1;
|
|
Request^.KeyIncl1 := aKeyIncl1;
|
|
Request^.FieldCount2 := aFieldCount2;
|
|
Request^.PartialLen2 := aPartialLen2;
|
|
Request^.KeyLen2 := KeyLen2;
|
|
Request^.KeyIncl2 := aKeyIncl2;
|
|
Move(aKeyData1^, Request^.KeyData1, KeyLen1);
|
|
ReqKeyData2 := PffByteArray(PAnsiChar(@Request^.KeyData1) + KeyLen1);
|
|
Move(akeyData2^, ReqKeyData2^, KeyLen2);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetRange,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetTimeout(aTimeout : Longint) : TffResult;
|
|
var
|
|
Request : TffnmCursorSetTimeoutReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
if prTimeout = aTimeout then Exit;
|
|
|
|
prTimeout := aTimeout;
|
|
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.Timeout := prTimeout;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetTimeout,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetToBegin : TffResult;
|
|
var
|
|
Request : TffnmCursorSetToBeginReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetToBegin,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetToBookmark(aBookmark : PffByteArray) : TffResult;
|
|
var
|
|
Request : PffnmCursorSetToBookmarkReq;
|
|
ReqLen : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
ReqLen := SizeOf(Request^) - 2 + BookMarkSize;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.BookmarkSize := BookMarkSize;
|
|
Move(aBookmark^, Request^.Bookmark, BookMarkSize);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetToBookmark,
|
|
Timeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetToCursor(aSourceCursor : TFFProxyCursor
|
|
) : TffResult;
|
|
var
|
|
Request : TffnmCursorSetToCursorReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.DestCursorID := SrCursorID;
|
|
Request.SrcCursorID := aSourceCursor.SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetToCursor,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetToEnd : TffResult;
|
|
var
|
|
Request : TffnmCursorSetToEndReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetToEnd,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SetToKey(aSearchAction : TffSearchKeyAction;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray) : TffResult;
|
|
var
|
|
Request : PffnmCursorSetToKeyReq;
|
|
ReqLen : Longint;
|
|
KeyDataLen : Longint;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
if aDirectKey then
|
|
KeyDataLen := Dictionary.IndexKeyLength[IndexID]
|
|
else
|
|
KeyDataLen := PhysicalRecordSize;
|
|
ReqLen := SizeOf(TffnmCursorSetToKeyReq) - 2 + KeyDataLen;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Initialize Request }
|
|
Request^.CursorID := SrCursorID;
|
|
Request^.Action := aSearchAction;
|
|
Request^.DirectKey := aDirectKey;
|
|
Request^.FieldCount := aFieldCount;
|
|
Request^.PartialLen := aPartialLen;
|
|
Request^.KeyDataLen := KeyDataLen;
|
|
Move(aKeyData^, Request^.KeyData, KeyDataLen);
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSetToKey,
|
|
Timeout,
|
|
Pointer(Request),
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.SwitchToIndex(aIndexName : TffDictItemName;
|
|
aIndexID : Longint;
|
|
aPosnOnRec : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmCursorSwitchToIndexReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.IndexName := aIndexName;
|
|
Request.IndexNumber := aIndexID;
|
|
Request.PosnOnRec := aPosnOnRec;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmCursorSwitchToIndex,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
if (Request.IndexName <> '') then begin
|
|
prIndexID := Dictionary.GetIndexFromName(Request.IndexName);
|
|
prIndexName := aIndexName;
|
|
end else begin
|
|
prIndexID := aIndexID;
|
|
prIndexName := Dictionary.IndexName[aIndexID];
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.TableGetRecCount(var aRecCount : Longint) : TffResult;
|
|
var
|
|
Request : TffnmGetTableRecCountReq;
|
|
Reply : PffnmGetTableRecCountRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmGetTableRecCount,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aRecCount := Reply^.RecCount;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{Begin !!.07}
|
|
{----------}
|
|
function TFFProxyCursor.TableGetRecCountAsync(var aTaskID : Longint) : TffResult;
|
|
var
|
|
Request : TffnmGetTableRecCountAsyncReq;
|
|
Reply : PffnmGetTableRecCountAsyncRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmGetTableRecCountAsync,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aTaskID := Reply^.RebuildID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{End !!.07}
|
|
{----------}
|
|
function TFFProxyCursor.TableIsLocked(aLockType : TffLockType;
|
|
var aIsLocked : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmIsTableLockedReq;
|
|
Reply : PffnmIsTableLockedRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmIsTableLocked,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if ResultOK(Result) then
|
|
aIsLocked := Reply^.IsLocked;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.TableLockAcquire(aLockType : TffLockType) : TffResult;
|
|
var
|
|
Request : TffnmAcqTableLockReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialzie Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.LockType := aLockType;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmAcqTableLock,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.TableLockRelease(aAllLocks : Boolean) : TffResult;
|
|
var
|
|
Request : TffnmRelTableLockReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.AllLocks := aAllLocks;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmRelTableLock,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{----------}
|
|
function TFFProxyCursor.TableSetAutoInc(aValue : TffWord32) : TffResult;
|
|
var
|
|
Request : TffnmSetTableAutoIncValueReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
{ Initialize Request }
|
|
Request.CursorID := SrCursorID;
|
|
Request.AutoIncValue := aValue;
|
|
|
|
Reply := nil;
|
|
Result := Client.ProcessRequest(ffnmSetTableAutoIncValue,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
{-TffProxySQLStmt--------------------------------------------------------------}
|
|
constructor TffProxySQLStmt.Create(aDatabase : TffProxyDatabase;
|
|
const aTimeout : longInt);
|
|
var
|
|
Request : TffnmSQLAllocReq;
|
|
Reply : PffnmSQLAllocRpy;
|
|
ReplyLen : Longint;
|
|
Result : TffResult;
|
|
begin
|
|
inherited Create;
|
|
|
|
psClient := aDatabase.Client;
|
|
psDatabase := aDatabase;
|
|
psTimeout := aTimeout;
|
|
|
|
{ Initialize Request }
|
|
Request.DatabaseID := aDatabase.SrDatabaseID;
|
|
Request.Timeout := aTimeout;
|
|
|
|
Reply := nil;
|
|
Result := psClient.ProcessRequest(ffnmSQLAlloc,
|
|
psTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
Check(Result);
|
|
|
|
psSrStmtID := Reply^.StmtID;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
|
|
end;
|
|
{----------}
|
|
destructor TffProxySQLStmt.Destroy;
|
|
var
|
|
Request : TffnmSQLFreeReq;
|
|
Reply : Pointer;
|
|
ReplyLen : Longint;
|
|
begin
|
|
|
|
if psSrStmtID > 0 then begin
|
|
{ Initialize Request }
|
|
Request.StmtID := psSrStmtID;
|
|
|
|
Reply := nil;
|
|
psClient.ProcessRequest(ffnmSQLFree,
|
|
psTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Reply,
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end;
|
|
|
|
psSrStmtID := 0;
|
|
psDatabase := nil;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
{----------}
|
|
function TffProxySQLStmt.Exec(aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Request : TffnmSQLExecReq;
|
|
ReplyLen : Longint;
|
|
SvrCursorID : TffCursorID;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
{ Initialize Request }
|
|
Request.StmtID := psSrStmtID;
|
|
Request.OpenMode := aOpenMode;
|
|
|
|
Result := psClient.ProcessRequest(ffnmSQLExec,
|
|
psTimeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
{ Was the execution successful? }
|
|
if Result = DBIERR_NONE then begin
|
|
{ Yes. Get the cursorID from the stream & open a proxy cursor. }
|
|
aStream.Position := 0;
|
|
aStream.Read(SvrCursorID, sizeOf(SvrCursorID));
|
|
aCursorID := SvrCursorID;
|
|
if aCursorID <> 0 then
|
|
Result := psDatabase.QueryOpen(SvrCursorID, aOpenMode, smShared, psTimeout,
|
|
aStream, aCursorID);
|
|
end;
|
|
|
|
{ Assumption: If an error occurs then the TffQuery component is responsible
|
|
for displaying the error message returned from the server. }
|
|
|
|
end;
|
|
{----------}
|
|
function TffProxySQLStmt.Prepare(aQueryText: PChar;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
QueryLen : Longint;
|
|
ReqLen : Longint;
|
|
Request : PffnmSQLPrepareReq;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
|
|
QueryLen := StrLen(aQueryText);
|
|
ReqLen := SizeOf(TffnmSQLPrepareReq) - SizeOf(TffVarMsgField) + QueryLen + 1;
|
|
FFGetZeroMem(Request, ReqLen);
|
|
try
|
|
{ Prepare the request. }
|
|
Request.StmtID := psSrStmtID;
|
|
Move(aQueryText^, Request^.Query, QueryLen);
|
|
|
|
Result := psClient.ProcessRequest(ffnmSQLPrepare,
|
|
psTimeout,
|
|
Request,
|
|
ReqLen,
|
|
nmdByteArray,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
|
|
{ Assumption: Upper levels are responsible for Stream contents. }
|
|
|
|
finally
|
|
FFFreeMem(Request, ReqLen);
|
|
end;
|
|
|
|
end;
|
|
{----------}
|
|
function TffProxySQLStmt.SetParams(aNumParams : word;
|
|
aParamDescs : pointer;
|
|
aDataBuffer : PffByteArray;
|
|
aDataLen : Longint;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
ReplyLen : Longint;
|
|
Stream : TMemoryStream;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
{ Output stream is expected to be:
|
|
StmtID (longint)
|
|
NumParams (word)
|
|
ParamList (array of TffSqlParamInfo)
|
|
BufLen (longint; size of DataBuffer)
|
|
DataBuffer (data buffer)
|
|
}
|
|
Stream := TMemoryStream.Create;
|
|
try
|
|
Stream.Write(psSrStmtID, SizeOf(psSrStmtID));
|
|
Stream.Write(aNumParams, SizeOf(aNumParams));
|
|
Stream.Write(aParamDescs^, aNumParams * SizeOf(TffSqlParamInfo));
|
|
Stream.Write(aDataLen, sizeOf(aDataLen));
|
|
Stream.Write(aDataBuffer^, aDataLen);
|
|
Stream.Position := 0;
|
|
|
|
Result := psClient.ProcessRequest(ffnmSQLSetParams,
|
|
psTimeout,
|
|
Stream.Memory,
|
|
Stream.Size,
|
|
nmdStream,
|
|
Pointer(aStream),
|
|
ReplyLen,
|
|
nmdStream);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
|
|
end;
|
|
{------------------------------------------------------------------------------}
|
|
|
|
{-TFFRemoteServerEngine--------------------------------------------------------}
|
|
function TFFRemoteServerEngine.BLOBCreate(aCursorID : TffCursorID;
|
|
var aBlobNr : TffInt64) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BlobCreate(aBlobNr);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBDelete(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBDelete(aBlobNr);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBFree(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
readOnly : Boolean) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBFree(aBlobNr,
|
|
ReadOnly);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBGetLength(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
var aLength : Longint) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBGetLength(aBlobNr,
|
|
aLength);
|
|
end;
|
|
{Begin !!.03}
|
|
{----------}
|
|
function TffRemoteServerEngine.BLOBListSegments(aCursorID : TffCursorID;
|
|
aBLOBNr : TffInt64;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Cursor : TffProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBListSegments(aBLOBNr, aStream);
|
|
end;
|
|
{End !!.03}
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBRead(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
aOffset : TffWord32; {!!.06}
|
|
aLen : TffWord32; {!!.06}
|
|
var aBLOB;
|
|
var aBytesRead : TffWord32) {!!.06}
|
|
: TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBRead(aBlobNr,
|
|
aOffset,
|
|
aLen,
|
|
aBLOB,
|
|
aBytesRead);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBTruncate(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
aBLOBLength : Longint) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBTruncate(aBlobNr,
|
|
aBLOBLength);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.BLOBWrite(aCursorID : TffCursorID;
|
|
aBlobNr : TffInt64;
|
|
aOffset : Longint;
|
|
aLen : Longint;
|
|
var aBLOB) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.BLOBWrite(aBlobNr,
|
|
aOffset,
|
|
aLen,
|
|
aBLOB);
|
|
end;
|
|
{Begin !!.01}
|
|
{----------}
|
|
function TffRemoteServerEngine.RemoteRestart(const aClientID : TffClientID) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.RemoteRestart;
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.RemoteStart(const aClientID : TffClientID) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.RemoteStart;
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.RemoteStop(const aClientID : TffClientID) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.RemoteStop;
|
|
end;
|
|
{End !!.01}
|
|
{----------}
|
|
procedure TFFRemoteServerEngine.scInitialize;
|
|
begin
|
|
{ do nothing }
|
|
end;
|
|
{----------}
|
|
procedure TffRemoteServerEngine.scPrepareForShutdown;
|
|
begin
|
|
{ do nothing }
|
|
end;
|
|
{----------}
|
|
procedure TffRemoteServerEngine.scShutdown;
|
|
begin
|
|
{ do nothing }
|
|
end;
|
|
{----------}
|
|
procedure TffRemoteServerEngine.scStartup;
|
|
begin
|
|
{ do nothing }
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.bseGetAutoSaveCfg : Boolean;
|
|
begin
|
|
{This is here to kill warnings. Clients shouldn't care about the
|
|
RSE's NoAutoSaveCfg setting.}
|
|
Result := False;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.bseGetReadOnly : Boolean;
|
|
var
|
|
Client : TffProxyClient;
|
|
begin
|
|
Client := GetDefaultClient;
|
|
if Assigned(Client) then
|
|
Result := Client.IsReadOnly
|
|
else
|
|
Result := False;
|
|
end;
|
|
{--------}
|
|
procedure TFFRemoteServerEngine.bseSetAutoSaveCfg(aValue : Boolean); {!!.01 - Start}
|
|
begin
|
|
{do nothing}
|
|
end;
|
|
{--------}
|
|
procedure TFFRemoteServerEngine.bseSetReadOnly(aValue : Boolean);
|
|
begin
|
|
{do nothing}
|
|
end;
|
|
{--------} {!!.01 - End}
|
|
procedure TFFRemoteServerEngine.FFNotificationEx(const AOp : Byte;
|
|
AFrom : TffComponent;
|
|
const AData : TffWord32);
|
|
var
|
|
CL : TFFProxyClient;
|
|
ClIdx : Longint;
|
|
ClFound : Boolean;
|
|
begin
|
|
inherited; {!!.11}
|
|
if (AFrom = Transport) then
|
|
if ((AOp = ffn_Destroy) or (AOp = ffn_Remove)) then begin
|
|
FFNotifyDependents(ffn_Deactivate);
|
|
rsTransport := nil;
|
|
end else if (AOp = ffn_Deactivate) then
|
|
FFNotifyDependents(ffn_Deactivate)
|
|
else if (AOp = ffn_ConnectionLost) then begin
|
|
{ If we manage this client, then notify depenents that connection is
|
|
lost. It is up to the baseclient dependents to check the data
|
|
parameter to see if this notification affects them.}
|
|
CL := nil;
|
|
ClFound := False;
|
|
with ClientList.BeginRead do
|
|
try
|
|
for ClIdx := 0 to Pred(ClientList.Count) do begin
|
|
CL := TFFProxyClient(ClientList[ClIdx].Key^);
|
|
if CL.pcSrClientID = AData then begin
|
|
ClFound := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
finally
|
|
EndRead;
|
|
end;
|
|
if CLFound then begin
|
|
ForceClosing(Longint(CL));
|
|
ClientRemove(Longint(CL));
|
|
FFNotifyDependentsEx(ffn_ConnectionLost, Longint(CL))
|
|
end;
|
|
end;
|
|
end;
|
|
{Begin !!.07}
|
|
{--------}
|
|
procedure TffRemoteServerEngine.Log(const aMsg : string);
|
|
begin
|
|
FEventLog.WriteString(aMsg);
|
|
end;
|
|
{--------}
|
|
procedure TffRemoteServerEngine.LogAll(const Msgs : array of string);
|
|
begin
|
|
FEventLog.WriteStrings(Msgs);
|
|
end;
|
|
{--------}
|
|
procedure TffRemoteServerEngine.LogFmt(const aMsg : string; args : array of const);
|
|
begin
|
|
FEventLog.WriteString(format(aMsg, args));
|
|
end;
|
|
{End !!.07}
|
|
{--------}
|
|
function TFFRemoteServerEngine.CheckClientIDAndGet(aClientID : TffClientID;
|
|
var aClient : TffProxyClient
|
|
) : TffResult;
|
|
begin
|
|
Result := DBIERR_INVALIDHNDL;
|
|
|
|
aClient := nil;
|
|
try
|
|
if (TObject(aClientID) is TFFProxyClient) then begin
|
|
aClient := TffProxyClient(aClientID);
|
|
Result := DBIERR_NONE;
|
|
end;
|
|
except
|
|
{ An exception may be raised if the ID is bogus. Swallow the exception.}
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CheckCursorIDAndGet(aCursorID : TffCursorID;
|
|
var aCursor : TffProxyCursor
|
|
) : TffResult;
|
|
begin
|
|
Result := DBIERR_INVALIDHNDL;
|
|
|
|
aCursor := nil;
|
|
try
|
|
if (TObject(aCursorID) is TFFProxyCursor) then begin
|
|
aCursor := TffProxyCursor(aCursorID);
|
|
Result := DBIERR_NONE;
|
|
end;
|
|
except
|
|
{ An exception may be raised if the ID is bogus. Swallow the exception.}
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.CheckStmtIDAndGet(aStmtID : TffSqlStmtID;
|
|
var aStmt : TffProxySQLStmt) : TffResult;
|
|
begin
|
|
Result := DBIERR_INVALIDHNDL;
|
|
|
|
aStmt := nil;
|
|
try
|
|
if (TObject(aStmtID) is TffProxySQLStmt) then begin
|
|
aStmt := TffProxySQLStmt(aStmtID);
|
|
Result := DBIERR_NONE;
|
|
end;
|
|
except
|
|
{ An exception may be raised if the ID is bogus. Swallow the exception.}
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CheckDatabaseIDAndGet(
|
|
aDatabaseID : TffDatabaseID;
|
|
var aDatabase : TffProxyDatabase
|
|
) : TffResult;
|
|
begin
|
|
Result := DBIERR_INVALIDHNDL;
|
|
|
|
aDatabase := nil;
|
|
try
|
|
if (TObject(aDatabaseID) is TFFProxyDatabase) then begin
|
|
aDatabase := TffProxyDatabase(aDatabaseID);
|
|
Result := DBIERR_NONE;
|
|
end;
|
|
except
|
|
{ An exception may be raised if the ID is bogus. Swallow the exception.}
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CheckSessionIDAndGet(aClientID : TffClientID;
|
|
aSessionID : TffSessionID;
|
|
var aClient : TffProxyClient;
|
|
var aSession : TffProxySession
|
|
) : TffResult;
|
|
begin
|
|
aSession := nil;
|
|
aClient := nil;
|
|
|
|
Result := CheckClientIDAndGet(aClientID, aClient);
|
|
if (Result = DBIERR_NONE) then begin
|
|
try
|
|
if (TObject(aSessionID) is TFFProxySession) then begin
|
|
aSession := TffProxySession(aSessionID)
|
|
end;
|
|
except
|
|
{ An exception may be raised if the ID is bogus. Swallow the exception.}
|
|
end;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.ClientAdd(var aClientID : TffClientID;
|
|
const aClientName : TffNetName;
|
|
const aUserID : TffName;
|
|
const aTimeout : Longint;
|
|
var aHash : TffWord32
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
ListItem : TffIntListItem;
|
|
|
|
begin
|
|
Result := DBIERR_NONE;
|
|
Client := nil;
|
|
|
|
{Create client object}
|
|
try
|
|
Client := TFFProxyClient.Create(rsTransport, aUserID, aHash, aTimeOut);
|
|
except
|
|
on E:Exception do
|
|
if (E is EffException) or
|
|
(E is EffDatabaseError) or
|
|
(E is EffServerComponentError) then
|
|
Result := EffException(E).ErrorCode;
|
|
end;
|
|
|
|
if ResultOK(Result) and Assigned(Client) then begin
|
|
{Add to the internal list}
|
|
ListItem := TffIntListItem.Create(Longint(Client));
|
|
with rsClientList.BeginWrite do
|
|
try
|
|
Insert(ListItem);
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
{Set the return value}
|
|
aClientID := Longint(Client);
|
|
end;
|
|
end;
|
|
{Begin !!.11}
|
|
function TffRemoteServerEngine.ClientAddEx(var aClientID : TffClientID;
|
|
const aClientName : TffNetName;
|
|
const aUserID : TffName;
|
|
const aTimeout : Longint;
|
|
const aClientVersion : Longint;
|
|
var aHash : TffWord32) : TffResult;
|
|
begin
|
|
Result := ClientAdd(aClientID, aClientName, aUserID, aTimeout, aHash);
|
|
end;
|
|
{End !!.11}
|
|
{----------}
|
|
function TFFRemoteServerEngine.ClientRemove(aClientID : TffClientID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
{Remove from the internal list, and free}
|
|
with rsClientList.BeginWrite do
|
|
try
|
|
Delete(Client); {!!.01}
|
|
Client.Free;
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.ClientSetTimeout(const aClientID : TffClientID;
|
|
const aTimeout : Longint
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.SetTimeout(aTimeout);
|
|
end;
|
|
{----------}
|
|
constructor TFFRemoteServerEngine.Create(aOwner : TComponent);
|
|
begin
|
|
inherited Create(aOwner);
|
|
|
|
rsClientList := TFFProxyClientList.Create;
|
|
rsTimeout := 0;
|
|
rsTransport := nil;
|
|
|
|
with RemoteServerEngines.BeginWrite do
|
|
try
|
|
Insert(TffIntListItem.Create(Longint(Self)));
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorClone(aCursorID : TffCursorID;
|
|
aOpenMode : TffOpenMode;
|
|
var aNewCursorID : TffCursorID
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.CursorClone(aOpenMode,
|
|
aNewCursorID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorClose(aCursorID : TffCursorID) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then begin
|
|
Database := Cursor.Database;
|
|
Result := Database.TableClose(Cursor);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorCompareBookmarks(
|
|
aCursorID : TffCursorID;
|
|
aBookmark1 : PffByteArray;
|
|
aBookmark2 : PffByteArray;
|
|
var aCompResult : Longint
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.CompareBookmarks(aBookmark1,
|
|
aBookmark2,
|
|
aCompResult);
|
|
end;
|
|
{Begin !!.02}
|
|
{----------}
|
|
function TffRemoteServerEngine.CursorCopyRecords(aSrcCursorID,
|
|
aDestCursorID : TffCursorID;
|
|
aCopyBLOBs : Boolean) : TffResult;
|
|
var
|
|
DestCursor, SrcCursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aDestCursorID, DestCursor);
|
|
if ResultOK(Result) then begin
|
|
Result := CheckCursorIDAndGet(aSrcCursorID, SrcCursor);
|
|
if ResultOK(Result) then
|
|
Result := DestCursor.CopyRecords(SrcCursor, aCopyBLOBs);
|
|
end;
|
|
end;
|
|
{End !!.02}
|
|
{Begin !!.06}
|
|
{----------}
|
|
function TffRemoteServerEngine.CursorDeleteRecords(aCursorID : TffCursorID) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.DeleteRecords;
|
|
end;
|
|
{End !!.06}
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorGetBookmark(aCursorID : TffCursorID;
|
|
aBookmark : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.GetBookmark(aBookmark);
|
|
end;
|
|
{Begin !!.03}
|
|
{----------}
|
|
function TffRemoteServerEngine.CursorListBLOBFreeSpace(aCursorID : TffCursorID;
|
|
const aInMemory : Boolean;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Cursor : TffProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.ListBLOBFreeSpace(aInMemory, aStream);
|
|
end;
|
|
{End !!.03}
|
|
{----------}
|
|
function TffRemoteServerEngine.CursorOverrideFilter(aCursorID : longint;
|
|
aExpression : pCANExpr;
|
|
aTimeout : TffWord32) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.OverrideFilter(aExpression, aTimeout);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.CursorRestoreFilter(aCursorID : longInt) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RestoreFilter;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorGetBookmarkSize(aCursorID : TffCursorID;
|
|
var aSize : Longint
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.GetBookmarkSize(aSize);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorResetRange(aCursorID : TffCursorID
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.ResetRange;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetFilter(aCursorID : TffCursorID;
|
|
aExpression : pCANExpr;
|
|
aTimeout : TffWord32
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetFilter(aExpression,
|
|
aTimeout);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetRange(aCursorID : TffCursorID;
|
|
aDirectKey : Boolean;
|
|
aFieldCount1 : Longint;
|
|
aPartialLen1 : Longint;
|
|
aKeyData1 : PffByteArray;
|
|
aKeyIncl1 : Boolean;
|
|
aFieldCount2 : Longint;
|
|
aPartialLen2 : Longint;
|
|
aKeyData2 : PffByteArray;
|
|
aKeyIncl2 : Boolean
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetRange(aDirectKey,
|
|
aFieldCount1,
|
|
aPartialLen1,
|
|
aKeyData1,
|
|
aKeyIncl1,
|
|
aFieldCount2,
|
|
aPartialLen2,
|
|
aKeyData2,
|
|
aKeyIncl2);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetTimeout(const aCursorID : TffCursorID;
|
|
const aTimeout : Longint
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetTimeout(aTimeout);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetToBegin(aCursorID : TffCursorID
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetToBegin;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetToBookmark(aCursorID : TffCursorID;
|
|
aBookmark : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetToBookmark(aBookmark);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetToCursor(aDestCursorID : TffCursorID;
|
|
aSrcCursorID : TffCursorID
|
|
) : TffResult;
|
|
var
|
|
DestCursor : TFFProxyCursor;
|
|
SourceCursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aDestCursorID, DestCursor);
|
|
if ResultOK(Result) then
|
|
Result := CheckCursorIDAndGet(aSrcCursorID, SourceCursor);
|
|
if ResultOK(Result) then
|
|
Result := DestCursor.SetToCursor(SourceCursor);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetToEnd(aCursorID : TffCursorID
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetToEnd;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSetToKey(
|
|
aCursorID : TffCursorID;
|
|
aSearchAction : TffSearchKeyAction;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SetToKey(aSearchAction,
|
|
aDirectKey,
|
|
aFieldCount,
|
|
aPartialLen,
|
|
aKeyData);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.CursorSwitchToIndex(aCursorID : TffCursorID;
|
|
aIndexName : TffDictItemName;
|
|
aIndexID : Longint;
|
|
aPosnOnRec : Boolean
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.SwitchToIndex(aIndexName,
|
|
aIndexID,
|
|
aPosnOnRec);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseAddAlias(const aAlias : TffName;
|
|
const aPath : TffPath;
|
|
aCheckSpace : Boolean; {!!.11}
|
|
const aClientID : TffClientID)
|
|
: TffResult;
|
|
var
|
|
Client : TffProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseAddAlias(aAlias, aPath, aCheckSpace); {!!.11}
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseAliasList(aList : TList;
|
|
aClientID : TffClientID)
|
|
: TffResult;
|
|
var
|
|
Client : TffProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseAliasList(aList);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecoveryAliasList(aList : TList;
|
|
aClientID : TffClientID)
|
|
: TffResult;
|
|
begin
|
|
Assert(False, 'RecoveryAliasList unsupported for TffRemoteServerEngine.');
|
|
Result := DBIERR_NOTSUPPORTED;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseChgAliasPath(aAlias : TffName;
|
|
aNewPath : TffPath;
|
|
aCheckSpace : Boolean; {!!.11}
|
|
aClientID : TffClientID)
|
|
: TffResult;
|
|
var
|
|
Client : TffProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseChgAliasPath(aAlias,
|
|
aNewPath,
|
|
aCheckSpace) {!!.11}
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseClose(aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then begin
|
|
Client := Database.Client;
|
|
Result := Client.DatabaseClose(Database);
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseDeleteAlias(aAlias : TffName;
|
|
aClientID : TffClientID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseDeleteAlias(aAlias)
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseGetAliasPath(aAlias : TffName;
|
|
var aPath : TffPath;
|
|
aClientID : TffClientID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseGetAliasPath(aAlias, aPath)
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseGetFreeSpace(const aDatabaseID : TffDatabaseID;
|
|
var aFreeSpace : Longint
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.GetDbFreeSpace(aFreeSpace);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.DatabaseModifyAlias(const aClientID : TffClientID;
|
|
const aAlias : TffName;
|
|
const aNewName : TffName;
|
|
const aNewPath : TffPath;
|
|
aCheckSpace : Boolean) {!!.11}
|
|
: TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseModifyAlias(aAlias,
|
|
aNewName,
|
|
aNewPath,
|
|
aCheckSpace) {!!.11}
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseOpen(aClientID : TffClientID;
|
|
const aAlias : TffName;
|
|
const aOpenMode : TffOpenMode;
|
|
const aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseOpen(aAlias,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
aDatabaseID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseOpenNoAlias(aClientID : TffClientID;
|
|
const aPath : TffPath;
|
|
const aOpenMode : TffOpenMode;
|
|
const aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.DatabaseOpenNoAlias(aPath,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
aDatabaseID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseSetTimeout(
|
|
const aDatabaseID : TffDatabaseID;
|
|
const aTimeout : Longint
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.SetTimeout(aTimeout);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.DatabaseTableExists(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aExists : Boolean
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableExists(aTableName, aExists);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.DatabaseTableList(aDatabaseID : TffDatabaseID;
|
|
const aMask : TffFileNameExt;
|
|
aList : TList
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableList(aMask,
|
|
aList);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.DatabaseTableLockedExclusive(
|
|
aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aLocked : Boolean
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableLockedExclusive(aTableName,
|
|
aLocked);
|
|
|
|
end;
|
|
{----------}
|
|
destructor TFFRemoteServerEngine.Destroy;
|
|
//var {!!.03}
|
|
// Idx : Longint; {!!.03}
|
|
begin
|
|
FFNotifyDependents(ffn_Destroy);
|
|
|
|
{ Make sure we are shutdown. }
|
|
State := ffesInactive;
|
|
|
|
{Begin !!.03}
|
|
// {Free dependent objects}
|
|
// with rsClientList.BeginWrite do
|
|
// try
|
|
// for Idx := 0 to Pred(Count) do
|
|
// TFFProxyClient(Items[Idx]).Free;
|
|
// finally
|
|
// EndWrite;
|
|
// end;
|
|
{End !!.03}
|
|
|
|
with RemoteServerEngines.BeginWrite do
|
|
try
|
|
Delete(Longint(Self)); {!!.01}
|
|
finally
|
|
EndWrite;
|
|
end;
|
|
|
|
{Free and nil internal lists}
|
|
rsClientList.Free;
|
|
rsClientList := nil;
|
|
|
|
{Clear the transport}
|
|
Transport := nil;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.FileBLOBAdd(aCursorID : TffCursorID;
|
|
const aFileName : TffFullFileName;
|
|
var aBlobNr : TffInt64) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.FileBLOBAdd(aFileName,
|
|
aBlobNr);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetDefaultClient: TFFProxyClient;
|
|
begin
|
|
Result := nil;
|
|
with rsClientList.BeginRead do
|
|
try
|
|
if Count > 0 then
|
|
Result := TFFProxyClient(TffIntListItem(Items[0]).KeyAsInt); {!!.01}
|
|
finally
|
|
EndRead;
|
|
end;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetServerDateTime(var aDateTime : TDateTime
|
|
) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetServerDateTime(aDateTime)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetServerSystemTime(var aSystemTime : TSystemTime) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetServerSystemTime(aSystemTime)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetServerGUID(var aGUID : TGUID) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetServerGUID(aGUID)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetServerID(var aUniqueID : TGUID) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetServerID(aUniqueID)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetServerStatistics(var Stats : TffServerStatistics) : TffResult;
|
|
begin;
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetServerStatistics(Stats)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetCommandHandlerStatistics(const CmdHandlerIdx : Integer;
|
|
var Stats : TffCommandHandlerStatistics) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetCommandHandlerStatistics(CmdHandlerIdx,
|
|
Stats)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.GetTransportStatistics(const CmdHandlerIdx : Integer;
|
|
const TransportIdx : Integer;
|
|
var Stats : TffTransportStatistics) : TffResult;
|
|
begin
|
|
if (GetDefaultClient <> nil) then
|
|
Result := GetDefaultClient.GetTransportStatistics(CmdHandlerIdx,
|
|
TransportIdx,
|
|
Stats)
|
|
else
|
|
Result := DBIERR_INVALIDHNDL;
|
|
end;
|
|
{----------} {end !!.07}
|
|
procedure TFFRemoteServerEngine.GetServerNames(aList: TStrings;
|
|
aTimeout : Longint);
|
|
begin
|
|
Transport.GetServerNames(aList, aTimeout);
|
|
end;
|
|
{----------}
|
|
procedure TFFRemoteServerEngine.ForceClosing(const aClientID : TffClientID);
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
if CheckClientIDAndGet(aClientID, Client) = DBIERR_NONE then
|
|
Client.ForceClosed := True;
|
|
end;
|
|
{Begin !!.06}
|
|
{--------}
|
|
function TffRemoteServerEngine.ProcessRequest(aClientID : TffClientID;
|
|
aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint;
|
|
aRequestDataType : TffNetMsgDataType;
|
|
var aReply : Pointer;
|
|
var aReplyLen : Longint;
|
|
aReplyType : TffNetMsgDataType) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.ProcessRequest(aMsgID, aTimeout, aRequestData,
|
|
aRequestDataLen, aRequestDataType,
|
|
aReply, aReplyLen, aReplyType);
|
|
end;
|
|
{--------}
|
|
function TffRemoteServerEngine.ProcessRequestNoReply(aClientID : TffClientID;
|
|
aMsgID : Longint;
|
|
aTimeout : Longint;
|
|
aRequestData : Pointer;
|
|
aRequestDataLen : Longint ) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.ProcessRequestNoReply(aMsgID, aTimeout, aRequestData,
|
|
aRequestDataLen);
|
|
end;
|
|
{End !!.06}
|
|
{----------}
|
|
function TFFRemoteServerEngine.RebuildGetStatus(aRebuildID : Longint;
|
|
const aClientID : TffClientID;
|
|
var aIsPresent : Boolean;
|
|
var aStatus : TffRebuildStatus
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.GetRebuildStatus(aRebuildID,
|
|
aIsPresent,
|
|
aStatus);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordDelete(aCursorID : TffCursorID;
|
|
aData : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordDelete(aData);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.RecordDeleteBatch(aCursorID : TffCursorID;
|
|
aBMCount : Longint;
|
|
aBMLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordDeleteBatch(aBMCount,
|
|
aBMLen,
|
|
aData,
|
|
aErrors);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordExtractKey(aCursorID : TffCursorID;
|
|
aData : PffByteArray;
|
|
aKey : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordExtractKey(aData,
|
|
aKey);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordGet(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordGet(aLockType,
|
|
aData);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordGetBatch(aCursorID : TffCursorID;
|
|
aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
var aRecRead : Longint;
|
|
aData : PffByteArray;
|
|
var aError : TffResult
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordGetBatch(aRecCount,
|
|
aRecLen,
|
|
aRecRead,
|
|
aData,
|
|
aError);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordGetForKey(aCursorID : TffCursorID;
|
|
aDirectKey : Boolean;
|
|
aFieldCount : Longint;
|
|
aPartialLen : Longint;
|
|
aKeyData : PffByteArray;
|
|
aData : PffByteArray;
|
|
aFirstCall : Boolean
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordGetForKey(aDirectKey,
|
|
aFieldCount,
|
|
aPartialLen,
|
|
aKeyData,
|
|
aData,
|
|
aFirstCall);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordGetNext(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordGetNext(aLockType,
|
|
aData);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordGetPrior(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordGetPrior(aLockType,
|
|
aData);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordInsert(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
aData : PffByteArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordInsert(aLockType,
|
|
aData);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordInsertBatch(aCursorID : TffCursorID;
|
|
aRecCount : Longint;
|
|
aRecLen : Longint;
|
|
aData : PffByteArray;
|
|
aErrors : PffLongintArray
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordInsertBatch(aRecCount,
|
|
aRecLen,
|
|
aData,
|
|
aErrors);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.RecordIsLocked(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
var aIsLocked : boolean) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordIsLocked(aLockType,
|
|
aIsLocked);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordModify(aCursorID : TffCursorID;
|
|
aData : PffByteArray;
|
|
aRelLock : Boolean) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordModify(aData,
|
|
aRelLock);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.RecordRelLock(aCursorID : TffCursorID;
|
|
aAllLocks : Boolean) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.RecordRelLock(aAllLocks);
|
|
end;
|
|
{----------}
|
|
procedure TFFRemoteServerEngine.rsSetTransport(const Value : TFFBaseTransport);
|
|
begin
|
|
if rsTransport = Value then
|
|
Exit;
|
|
|
|
FFNotifyDependents(ffn_Deactivate);
|
|
if Assigned(rsTransport) then
|
|
rsTransport.FFRemoveDependent(Self);
|
|
|
|
rsTransport := Value;
|
|
if Assigned(rsTransport) then
|
|
rsTransport.FFAddDependent(Self);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionAdd(const aClientID : TffClientID;
|
|
const aTimeout : Longint;
|
|
var aSessionID : TffSessionID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Result := Client.SessionAdd(aSessionID, aTimeout);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionCount(aClientID : TffClientID;
|
|
var aCount : Longint) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
aCount := Client.SessionCount;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionGetCurrent(aClientID : TffClientID;
|
|
var aSessionID : TffSessionID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
Session : TFFProxySession;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then begin
|
|
Session := Client.CurrentSession;
|
|
aSessionID := Longint(Session);
|
|
end;
|
|
end;
|
|
{Begin !!.06}
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionCloseInactiveTables(aClientID : TffClientID) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
begin
|
|
Result := CheckClientIDAndGet(aClientID, Client);
|
|
if ResultOK(Result) then
|
|
Client.SessionCloseInactiveTables;
|
|
end;
|
|
{End !!.06}
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionRemove(aClientID : TffClientID;
|
|
aSessionID : TffSessionID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
Session : TFFProxySession;
|
|
begin
|
|
Result := CheckSessionIDAndGet(aClientID, aSessionID, Client, Session);
|
|
if ResultOK(Result) then
|
|
Client.SessionRemove(Session);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionSetCurrent(aClientID : TffClientID;
|
|
aSessionID : TffSessionID
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
Session : TFFProxySession;
|
|
begin
|
|
Result := CheckSessionIDAndGet(aClientID, aSessionID, Client, Session);
|
|
if ResultOK(Result) then
|
|
Client.SessionSetCurrent(Session);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SessionSetTimeout(
|
|
const aClientID : TffClientID;
|
|
const aSessionID : TffSessionID;
|
|
const aTimeout : Longint
|
|
) : TffResult;
|
|
var
|
|
Client : TFFProxyClient;
|
|
Session : TFFProxySession;
|
|
begin
|
|
Result := CheckSessionIDAndGet(aClientID, aSessionID, Client, Session);
|
|
if ResultOK(Result) then
|
|
Result := Session.SetTimeout(aTimeout);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLAlloc(aClientID : TffClientID;
|
|
aDatabaseID : TffDatabaseID;
|
|
aTimeout : longInt;
|
|
var aStmtID : TffSqlStmtID) : TffResult;
|
|
var
|
|
Database : TffProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.SQLAlloc(aTimeout, aStmtID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLExec(aStmtID : TffSqlStmtID;
|
|
aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Statement : TffProxySQLStmt;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckStmtIDAndGet(aStmtID, Statement);
|
|
if ResultOK(Result) then
|
|
Result := Statement.Exec(aOpenMode, aCursorID, aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLExecDirect(aClientID : TffClientID;
|
|
aDatabaseID : TffDatabaseID;
|
|
aQueryText : PChar;
|
|
aTimeout : longInt;
|
|
aOpenMode : TffOpenMode;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Database : TffProxyDatabase;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.SQLExecDirect(aQueryText, aOpenMode, aTimeout,
|
|
aCursorID, aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLFree(aStmtID : TffSqlStmtID) : TffResult;
|
|
var
|
|
Statement : TffProxySQLStmt;
|
|
begin
|
|
{ Assumption: The cursor associated with the SQL statement has already been
|
|
closed. }
|
|
Result := CheckStmtIDAndGet(aStmtID, Statement);
|
|
if Result = DBIERR_NONE then
|
|
Statement.Free;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLPrepare(aStmtID : TffSqlStmtID;
|
|
aQueryText : PChar;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Statement : TffProxySQLStmt;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckStmtIDAndGet(aStmtID, Statement);
|
|
if Result = DBIERR_NONE then
|
|
Result := Statement.Prepare(aQueryText, aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.SQLSetParams(aStmtID : TffSqlStmtID;
|
|
aNumParams : word;
|
|
aParamDescs : pointer;
|
|
aDataBuffer : PffByteArray;
|
|
aDataLen : Longint;
|
|
aStream : TStream
|
|
) : TffResult;
|
|
var
|
|
Statement : TffProxySQLStmt;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckStmtIDAndGet(aStmtID, Statement);
|
|
if Result = DBIERR_NONE then
|
|
Result := Statement.SetParams(aNumParams, aParamDescs, aDataBuffer, aDataLen, aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableAddIndex(
|
|
const aDatabaseID : TffDatabaseID;
|
|
const aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexDesc: TffIndexDescriptor
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableAddIndex(aCursorID,
|
|
aTableName,
|
|
aIndexDesc);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableBuild(aDatabaseID : TffDatabaseID;
|
|
aOverWrite : Boolean;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aDictionary : TffDataDictionary
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableBuild(aOverWrite,
|
|
aTableName,
|
|
aForServer,
|
|
aDictionary);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableDelete(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableDelete(aTableName);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableDropIndex(aDatabaseID : TffDatabaseID;
|
|
aCursorID : TffCursorID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffDictItemName;
|
|
aIndexID : Longint
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableDropIndex(aCursorID,
|
|
aTablename,
|
|
aIndexName,
|
|
aIndexID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableEmpty(aDatabaseID : TffDatabaseID;
|
|
aCursorID : TffCursorID;
|
|
const aTableName : TffTableName
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableEmpty(aCursorID,
|
|
aTableName);
|
|
end;
|
|
{----------}
|
|
function TffRemoteServerEngine.TableGetAutoInc(aCursorID : TffCursorID;
|
|
var aValue : TffWord32) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableGetAutoInc(aValue);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableGetDictionary(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
aForServer : Boolean;
|
|
aStream : TStream
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableGetDictionary(aTableName,
|
|
aForServer,
|
|
aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableGetRecCount(aCursorID : TffCursorID;
|
|
var aRecCount : Longint
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableGetRecCount(aRecCount);
|
|
end;
|
|
{Begin !!.07}
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableGetRecCountAsync(aCursorID : TffCursorID;
|
|
var aTaskID : Longint) : TffResult;
|
|
var
|
|
Cursor : TffProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableGetRecCountAsync(aTaskID);
|
|
end;
|
|
{End !!.07}
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableIsLocked(aCursorID : TffCursorID;
|
|
aLockType : TffLockType;
|
|
var aIsLocked : Boolean) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableIsLocked(aLockType,
|
|
aIsLocked);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableLockAcquire(aCursorID : TffCursorID;
|
|
aLockType : TffLockType
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableLockAcquire(aLockType);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableLockRelease(aCursorID : TffCursorID;
|
|
aAllLocks : Boolean
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableLockRelease(aAllLocks);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableOpen(const aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
const aForServer : Boolean;
|
|
const aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
const aOpenMode : TffOpenMode;
|
|
aShareMode : TffShareMode;
|
|
const aTimeout : Longint;
|
|
var aCursorID : TffCursorID;
|
|
aStream : TStream) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Assert(Assigned(aStream));
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableOpen(aTableName,
|
|
aForServer,
|
|
aIndexName,
|
|
aIndexID,
|
|
aOpenMode,
|
|
aShareMode,
|
|
aTimeout,
|
|
aCursorID,
|
|
aStream);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TablePack(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aRebuildID : Longint) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TablePack(aTableName,
|
|
aRebuildID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableRebuildIndex(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
const aIndexName : TffName;
|
|
aIndexID : Longint;
|
|
var aRebuildID : Longint
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableRebuildIndex(aTableName,
|
|
aIndexName,
|
|
aIndexID,
|
|
aRebuildID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableRename(aDatabaseID : TffDatabaseID;
|
|
const aOldName : TffName;
|
|
const aNewName : TffName) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableRename(aOldName,
|
|
aNewName);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableRestructure(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
aDictionary : TffDataDictionary;
|
|
aFieldMap : TffStringList;
|
|
var aRebuildID : Longint
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TableRestructure(aTableName,
|
|
aDictionary,
|
|
aFieldMap,
|
|
aRebuildID);
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableSetAutoInc(aCursorID : TffCursorID;
|
|
aValue : TffWord32
|
|
) : TffResult;
|
|
var
|
|
Cursor : TFFProxyCursor;
|
|
begin
|
|
Result := CheckCursorIDAndGet(aCursorID, Cursor);
|
|
if ResultOK(Result) then
|
|
Result := Cursor.TableSetAutoInc(aValue);
|
|
end;
|
|
{Begin !!.11}
|
|
{----------}
|
|
function TFFRemoteServerEngine.TableVersion(aDatabaseID : TffDatabaseID;
|
|
const aTableName : TffTableName;
|
|
var aVersion : Longint) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
Request : TffnmGetTableVersionReq;
|
|
Reply : PffnmGetTableVersionRpy;
|
|
ReplyLen : Longint;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then begin
|
|
aVersion := 0;
|
|
{ Initialize Request }
|
|
Request.DatabaseID := Database.SrDatabaseID;
|
|
Request.TableName := aTableName;
|
|
|
|
Reply := nil;
|
|
Result := Database.pdClient.ProcessRequest(ffnmGetTableVersion,
|
|
Timeout,
|
|
@Request,
|
|
SizeOf(Request),
|
|
nmdByteArray,
|
|
Pointer(Reply),
|
|
ReplyLen,
|
|
nmdByteArray);
|
|
|
|
if ResultOK(Result) then
|
|
aVersion := Reply^.Version;
|
|
|
|
if Assigned(Reply) then
|
|
FFFreeMem(Reply, ReplyLen);
|
|
end; { if }
|
|
end;
|
|
{End !!.11}
|
|
{----------}
|
|
function TFFRemoteServerEngine.TransactionCommit(
|
|
const aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TransactionCommit;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TransactionRollback(
|
|
const aDatabaseID : TffDatabaseID
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TransactionRollback;
|
|
end;
|
|
{----------}
|
|
function TFFRemoteServerEngine.TransactionStart(
|
|
const aDatabaseID : TffDatabaseID;
|
|
const aFailSafe : Boolean
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TransactionStart(aFailSafe);
|
|
end;
|
|
{Begin !!.10}
|
|
{----------}
|
|
function TFFRemoteServerEngine.TransactionStartWith(
|
|
const aDatabaseID : TffDatabaseID;
|
|
const aFailSafe : Boolean;
|
|
const aCursorIDs : TffPointerList
|
|
) : TffResult;
|
|
var
|
|
Database : TFFProxyDatabase;
|
|
begin
|
|
Result := CheckDatabaseIDAndGet(aDatabaseID, Database);
|
|
if ResultOK(Result) then
|
|
Result := Database.TransactionStartWith(aFailSafe, aCursorIDs);
|
|
end;
|
|
{End !!.10}
|
|
{----------}
|
|
|
|
initialization
|
|
RemoteServerEngines := TffThreadList.Create;
|
|
|
|
finalization
|
|
RemoteServerEngines.Free;
|
|
RemoteServerEngines := nil;
|
|
|
|
end.
|