git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.SDAC@3 6f543ec7-021b-7e4c-98c9-62eafc7fb9a8
1697 lines
40 KiB
ObjectPascal
1697 lines
40 KiB
ObjectPascal
|
|
//////////////////////////////////////////////////
|
|
// DB Access Components
|
|
// Copyright © 1998-2007 Core Lab. All right reserved.
|
|
// Core Access
|
|
// Created: 01.07.00
|
|
//////////////////////////////////////////////////
|
|
|
|
{$IFNDEF CLR}
|
|
|
|
{$I Dac.inc}
|
|
|
|
unit CRAccess;
|
|
{$ENDIF}
|
|
interface
|
|
uses
|
|
{$IFDEF VER6P}
|
|
Variants,
|
|
{$ENDIF}
|
|
{$IFDEF CLR}
|
|
System.Runtime.InteropServices, Borland.Vcl.TypInfo,
|
|
{$ELSE}
|
|
CLRClasses,
|
|
{$ENDIF}
|
|
SysUtils, Classes, MemData, MemUtils;
|
|
|
|
const
|
|
// Props
|
|
prUsername = 1; // char*
|
|
prPassword = 2; // char*
|
|
prServer = 4; // char*
|
|
prAutoCommit = 5; // bool
|
|
prSQL = 10; // char*
|
|
prScanParams = 11; // bool
|
|
prSQLType = 12; // integer
|
|
prRowsProcessed = 13; // integer
|
|
|
|
prUniDirectional = 20; // bool
|
|
prFetchRows = 21; // integer
|
|
prFetchAll = 22; // bool
|
|
prRowsFetched = 23; // integer
|
|
prExecuting = 24; // bool
|
|
prLongStrings = 25; // bool
|
|
|
|
/// if False then PutField set Null for string fields with empty value ('')
|
|
prEnableEmptyStrings = 26; // bool
|
|
|
|
prFlatBuffers = 27; // bool
|
|
prConvertEOL = 28; // bool
|
|
prIndexFieldNames = 29; // char*
|
|
{$IFDEF HAVE_COMPRESS}
|
|
prCompressBlobMode = 30; // TCompressBlobMode
|
|
{$ENDIF}
|
|
prDisconnectedMode = 31;
|
|
prDisableParamScan = 32; // Used for ODAC
|
|
|
|
// Sub data types
|
|
const
|
|
dtSingle = 1;
|
|
dtUInt8 = 2;
|
|
|
|
type
|
|
TCRConnection = class;
|
|
TCRCommand = class;
|
|
TCRRecordSet = class;
|
|
TParamDesc = class;
|
|
TParamDescs = class;
|
|
|
|
TParamDescClass = class of TParamDesc;
|
|
|
|
TCommandType = (ctUnknown, ctStatement, ctCursor);
|
|
|
|
TCursorState = (
|
|
csInactive, // default state (TCRRecordSet.InternalOpen, TCustomDASQL.SQLChanged)
|
|
csOpen, // ODAC only: OCI73 TOCICommand.InternalOpen
|
|
csParsed, // ODAC only: OCI73 - statement parsed
|
|
csPrepared, // statement prepared
|
|
csBound, // ODAC only: parameters bound
|
|
csExecuteFetchAll, // ODAC only:
|
|
csExecuting, // ODAC only(?): statement is executing (TCRCommand.Execute)
|
|
csExecuted, // statement successfully executed
|
|
csFetching, // setted on first TCRRecordSet.Fetch
|
|
csFetchingAll, // ODAC, IbDAC specific. Setted on the FetchAll start
|
|
csFetched // fetch finished or canceled
|
|
);
|
|
|
|
TErrorProc = procedure (E: Exception; var Fail, Reconnect: boolean {$IFNDEF LITE}; var Reexecute: boolean; ReconnectAttempt: integer;
|
|
var ConnLostCause: TConnLostCause{$ENDIF}) of object;
|
|
TReconnectProc = procedure of object;
|
|
TBoolProc = procedure (Value: boolean) of object;
|
|
TBeforeFetchProc = procedure (out Cancel: boolean) of object;
|
|
TAfterFetchProc = procedure of object;
|
|
TDataChangeProc = procedure of object;
|
|
|
|
EFailOver = class(Exception)
|
|
public
|
|
FConnLostCause: TConnLostCause;
|
|
|
|
constructor Create(ConnLostCause: TConnLostCause);
|
|
end;
|
|
|
|
{ TCRConnection }
|
|
|
|
TCRConnection = class
|
|
private
|
|
FOnError: TErrorProc;
|
|
FOnReconnectError: TReconnectProc;
|
|
FOnReconnectSuccess: TReconnectProc;
|
|
FConnectionTime: Longword;
|
|
|
|
protected
|
|
FConnected: boolean;
|
|
FUsername: string;
|
|
FPassword: string;
|
|
FServer: string;
|
|
FAutoCommit: boolean;
|
|
FConvertEOL: boolean;
|
|
FIsValid: boolean;
|
|
FPool: TObject;
|
|
FPoolVersion: integer;
|
|
FComponent: TObject;
|
|
FDisconnectedMode: boolean;
|
|
|
|
FInProcessError: boolean;
|
|
FReconnected: boolean;
|
|
procedure DoError(E: Exception; var Fail: boolean); virtual;
|
|
|
|
property AutoCommit: boolean read FAutoCommit write FAutoCommit;
|
|
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure Connect(const ConnectString: string); virtual;
|
|
procedure Disconnect; virtual; abstract;
|
|
|
|
procedure StartTransaction; virtual; abstract;
|
|
procedure Commit; virtual; abstract;
|
|
procedure Rollback; virtual; abstract;
|
|
|
|
function GetConnected: boolean;
|
|
procedure SetConnected(Value: boolean);
|
|
|
|
procedure SetUsername(const Value: string); virtual;
|
|
procedure SetPassword(const Value: string); virtual;
|
|
procedure SetServer(const Value: string);
|
|
|
|
function CheckIsValid: boolean; virtual; abstract;
|
|
{$IFNDEF LITE}
|
|
procedure ReturnToPool; virtual;
|
|
{$ENDIF}
|
|
|
|
function SetProp(Prop: integer; const Value: variant): boolean; virtual;
|
|
function GetProp(Prop: integer; var Value: variant): boolean; virtual;
|
|
|
|
property OnError: TErrorProc read FOnError write FOnError;
|
|
property OnReconnectError: TReconnectProc read FOnReconnectError write FOnReconnectError;
|
|
property OnReconnectSuccess: TReconnectProc read FOnReconnectSuccess write FOnReconnectSuccess;
|
|
|
|
property ConnectionTime: Longword read FConnectionTime;
|
|
property IsValid: boolean read FIsValid write FIsValid;
|
|
property Pool: TObject read FPool write FPool;
|
|
property PoolVersion: integer read FPoolVersion write FPoolVersion;
|
|
property Component: TObject read FComponent write FComponent; // Is needed for failover
|
|
property DisconnectedMode: boolean read FDisconnectedMode write FDisconnectedMode;
|
|
end;
|
|
|
|
{ TCRCommand }
|
|
|
|
TCRCommand = class
|
|
private
|
|
protected
|
|
FComponent: TObject;
|
|
FConnection: TCRConnection;
|
|
FSQL: string;
|
|
FParams: TParamDescs;
|
|
FAutoCommit: boolean;
|
|
FAfterExecute: TBoolProc;
|
|
FExecuting: boolean;
|
|
{$IFDEF HAVE_COMPRESS}
|
|
FCompressBlob: TCompressBlobMode;
|
|
{$ENDIF}
|
|
|
|
property Params: TParamDescs read FParams write FParams;
|
|
property Executing: boolean read FExecuting write FExecuting;
|
|
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure Prepare; virtual;
|
|
procedure Unprepare; virtual;
|
|
function GetPrepared: boolean; virtual; abstract;
|
|
|
|
procedure Execute(Iters: integer = 1); virtual; abstract;
|
|
|
|
procedure SetConnection(Value: TCRConnection); virtual;
|
|
procedure SetSQL(const Value: string); virtual;
|
|
function GetCursorState: TCursorState; virtual; abstract;
|
|
procedure SetCursorState(Value: TCursorState); virtual; abstract;
|
|
|
|
{ Params }
|
|
function GetParamDescType: TParamDescClass; virtual;
|
|
procedure ClearParams;
|
|
function AddParam: TParamDesc; virtual;
|
|
procedure DeleteParam(Index: integer);
|
|
function GetParamCount: integer;
|
|
function GetParam(Index: integer): TParamDesc;
|
|
function FindParam(Name: string): TParamDesc;
|
|
|
|
function SetProp(Prop: integer; const Value: variant): boolean; virtual;
|
|
function GetProp(Prop: integer; var Value: variant): boolean; virtual;
|
|
|
|
property SQL: string read FSQL write SetSQL;
|
|
property Component: TObject read FComponent write FComponent; // Is needed for failover
|
|
property AfterExecute: TBoolProc read FAfterExecute write FAfterExecute;
|
|
end;
|
|
|
|
{ $IFNDEF LITE}
|
|
{ TCRTableInfo }
|
|
|
|
TCRTablesInfo = class;
|
|
|
|
TCRTableInfo = class(TObject)
|
|
protected
|
|
FOwner: TCRTablesInfo;
|
|
FIndex: Integer;
|
|
FTableName: string;
|
|
FTableAlias: string;
|
|
FIsView: boolean;
|
|
procedure SetTableName(Value: string);
|
|
procedure SetTableAlias(Value: string);
|
|
function GetTableNameFull: string; virtual;
|
|
procedure SetTableNameFull(Value: string); virtual;
|
|
public
|
|
constructor Create(Owner: TCRTablesInfo); virtual;
|
|
|
|
class function NormalizeName(Value: string; const QuoteNames: boolean = False): string; overload; virtual;
|
|
class function NormalizeName(Value: string; const LeftQ: char; const RightQ: char; const QuoteNames: boolean = False): string; overload; virtual;
|
|
|
|
class function LeftQuote: Char; virtual;
|
|
class function RightQuote: Char; virtual;
|
|
|
|
class function Quote(const Value: string; const LeftQ: char; const RightQ: char): string;
|
|
class function UnQuote(const Value: string): string;
|
|
class function IsQuoted(const Value: string): boolean; virtual;
|
|
class function QuotesNeeded(Value: string): boolean; virtual;
|
|
|
|
property TableName: string read FTableName write SetTableName;
|
|
property TableAlias: string read FTableAlias write SetTableAlias;
|
|
property TableNameFull: string read GetTableNameFull write SetTableNameFull;
|
|
property IsView: boolean read FIsView write FIsView;
|
|
property Index: Integer read FIndex write FIndex;
|
|
end;
|
|
|
|
TTableInfoClass = class of TCRTableInfo;
|
|
|
|
TCRTablesInfo = class
|
|
private
|
|
function GetItem(Index: Integer): TCRTableInfo;
|
|
procedure SetItem(Index: Integer; const Value: TCRTableInfo);
|
|
protected
|
|
FList: array of TCRTableInfo;
|
|
FUpdateCount: Integer;
|
|
FTableInfoClass: TTableInfoClass;
|
|
FTableNameList: TStringList;
|
|
FTableAliasList: TStringList;
|
|
FIsNormalized: Boolean;
|
|
procedure InternalAdd(TableInfo: TCRTableInfo);
|
|
procedure Changed;
|
|
procedure TableNameChanged;
|
|
procedure TableAliasChanged;
|
|
function GetCount: Integer;
|
|
public
|
|
constructor Create(TableInfoClass: TTableInfoClass);
|
|
destructor Destroy; override;
|
|
function Add: TCRTableInfo;
|
|
procedure Clear;
|
|
procedure BeginUpdate; virtual;
|
|
procedure EndUpdate; virtual;
|
|
procedure Normalize;
|
|
function FindByName(TableName: string): TCRTableInfo;
|
|
function IndexOf(TableInfo: TCRTableInfo): Integer;
|
|
function IndexByName(TableName: string): Integer;
|
|
function IndexByAlias(TableAlias: string): Integer;
|
|
property Items[Index: Integer]: TCRTableInfo read GetItem write SetItem; default;
|
|
property Count: Integer read GetCount;
|
|
property TableInfoClass: TTableInfoClass read FTableInfoClass;
|
|
end;
|
|
{ $ENDIF}
|
|
|
|
{ TCRFieldDesc}
|
|
|
|
TCRFieldDesc = class (TFieldDesc)
|
|
{ $IFNDEF LITE}
|
|
protected
|
|
FTableInfo: TCRTableInfo;
|
|
FActualNameQuoted: array[boolean] of string; // cache for [QuoteNames]
|
|
public
|
|
function ActualNameQuoted(RecordSet: TCRRecordSet; const QuoteNames: boolean): string; virtual;
|
|
|
|
property TableInfo: TCRTableInfo read FTableInfo write FTableInfo;
|
|
{ $ENDIF}
|
|
end;
|
|
|
|
{ TCRRecordSet }
|
|
|
|
TCRRecordSet = class (TMemData)
|
|
private
|
|
protected
|
|
FCommand: TCRCommand;
|
|
FUniDirectional: boolean;
|
|
FFetchRows: integer;
|
|
FFetchAll: boolean;
|
|
FLongStrings: boolean;
|
|
FFlatBuffers: boolean;
|
|
|
|
FAfterExecFetch: TBoolProc;
|
|
FAfterFetchAll: TBoolProc;
|
|
FOnBeforeFetch: TBeforeFetchProc;
|
|
FOnAfterFetch: TAfterFetchProc;
|
|
FOnDataChanged: TDataChangeProc;
|
|
FWaitForFetchBreak: boolean;
|
|
FCommandType: TCommandType;
|
|
|
|
{ $IFNDEF LITE}
|
|
FTablesInfo: TCRTablesInfo;
|
|
{ $ENDIF}
|
|
|
|
procedure CreateCommand; virtual; abstract;
|
|
procedure FreeCommand;
|
|
procedure SetCommand(Value: TCRCommand); virtual;
|
|
|
|
function CanFetchBack: boolean; virtual; // Return True, if BlockMan is store only one block of records
|
|
|
|
{ Open/Close }
|
|
procedure InternalPrepare; override;
|
|
procedure InternalUnPrepare; override;
|
|
procedure InternalOpen; override;
|
|
|
|
function NeedInitFields: boolean; virtual;
|
|
procedure ExecFetch; virtual;
|
|
procedure DoBeforeFetch(out Cancel: boolean); virtual;
|
|
procedure DoAfterFetch; virtual;
|
|
|
|
{ Items/Data }
|
|
// procedure PrepareData; override;
|
|
|
|
{ Fields }
|
|
function NeedConvertEOL: boolean; override;
|
|
|
|
{ TablesInfo }
|
|
class function GetTableInfoClass: TTableInfoClass; virtual;
|
|
|
|
function GetComponent: TObject;
|
|
procedure SetComponent(Value: TObject);
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
|
|
{ Fields}
|
|
function GetFieldDescType: TFieldDescClass; override;
|
|
|
|
{ Open/Close }
|
|
procedure Prepare; override;
|
|
procedure UnPrepare; override;
|
|
procedure Disconnect; virtual;
|
|
|
|
procedure Open; override;
|
|
procedure Close; override;
|
|
procedure ExecCommand; virtual; // Execute command
|
|
|
|
{ Records }
|
|
procedure GetNextRecord(RecBuf: IntPtr); override;
|
|
procedure GetPriorRecord(RecBuf: IntPtr); override;
|
|
|
|
{ Fetch }
|
|
procedure FetchAll; virtual;
|
|
procedure BreakFetch; virtual;// Breaks fetch. Can be called from other thread or in non-blocking mode
|
|
function CanDisconnect: boolean; virtual;
|
|
|
|
function RowsReturn: boolean; virtual;
|
|
|
|
function GetCommand: TCRCommand;
|
|
procedure SetConnection(Value: TCRConnection); virtual;
|
|
procedure SetSQL(const Value: string); virtual;
|
|
|
|
function SetProp(Prop: integer; const Value: variant): boolean; virtual;
|
|
function GetProp(Prop: integer; var Value: variant): boolean; virtual;
|
|
|
|
{ Filter }
|
|
procedure FilterUpdated; override;
|
|
|
|
property CommandType: TCommandType read FCommandType write FCommandType;
|
|
property AfterExecFetch: TBoolProc read FAfterExecFetch write FAfterExecFetch;
|
|
property AfterFetchAll: TBoolProc read FAfterFetchAll write FAfterFetchAll;
|
|
property OnBeforeFetch: TBeforeFetchProc read FOnBeforeFetch write FOnBeforeFetch;
|
|
property OnAfterFetch: TAfterFetchProc read FOnAfterFetch write FOnAfterFetch;
|
|
property OnDataChanged: TDataChangeProc read FOnDataChanged write FOnDataChanged;
|
|
|
|
{ Sorting }
|
|
procedure SortItems; override;
|
|
|
|
{ $IFNDEF LITE}
|
|
{ TablesInfo }
|
|
property TablesInfo: TCRTablesInfo read FTablesInfo;
|
|
{ $ENDIF}
|
|
property Component: TObject read GetComponent write SetComponent;
|
|
end;
|
|
|
|
{ TParamDesc }
|
|
|
|
TParamDirection = (pdUnknown, pdInput, pdOutput, pdInputOutput, pdResult);
|
|
|
|
TParamDesc = class
|
|
private
|
|
protected
|
|
FName: string;
|
|
FDataType: word;
|
|
FParamType: TParamDirection;
|
|
|
|
FSize: integer;
|
|
FData: variant; // pointer;
|
|
FIsNull: boolean;
|
|
FConvertEOL: boolean;
|
|
|
|
property Name: string read FName write FName;
|
|
property DataType: word read FDataType write FDataType;
|
|
property ParamType: TParamDirection read FParamType write FParamType;
|
|
property Size: integer read FSize write FSize;
|
|
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure Clear;
|
|
|
|
function GetName: string;
|
|
procedure SetName(Value: string);
|
|
|
|
function GetDataType: word;
|
|
procedure SetDataType(Value: word); virtual;
|
|
|
|
function GetParamType: TParamDirection;
|
|
procedure SetParamType(Value: TParamDirection);
|
|
|
|
function GetSize: integer;
|
|
procedure SetSize(Value: integer); virtual;
|
|
|
|
function GetValue: variant; virtual;
|
|
procedure SetValue(const Value: variant); virtual;
|
|
|
|
function GetObject: TSharedObject; virtual;
|
|
procedure SetObject(Value: TSharedObject); virtual;
|
|
|
|
function GetNull: boolean; virtual;
|
|
procedure SetNull(const Value: boolean); virtual;
|
|
|
|
procedure SetConvertEOL(const Value: boolean);
|
|
|
|
property Value: variant read FData write SetValue;
|
|
end;
|
|
|
|
{ TParamDescs }
|
|
|
|
TParamDescs = class (TDAList)
|
|
private
|
|
function GetItems(Index: integer): TParamDesc;
|
|
|
|
public
|
|
destructor Destroy; override;
|
|
|
|
procedure Clear; override;
|
|
|
|
function FindParam(Name: string): TParamDesc;
|
|
function ParamByName(Name: string): TParamDesc;
|
|
|
|
property Items[Index: integer]: TParamDesc read GetItems; default;
|
|
end;
|
|
|
|
{$IFDEF LINUX}
|
|
function GetTickCount: Cardinal;
|
|
{$ENDIF}
|
|
function GenerateTableName(const FieldDesc: TFieldDesc): string;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFNDEF LITE}
|
|
CRConnectionPool,
|
|
{$ENDIF}
|
|
{$IFDEF VER6P}
|
|
RTLConsts,
|
|
{$ELSE}
|
|
Consts,
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
Libc;
|
|
{$ELSE}
|
|
Windows;
|
|
{$ENDIF}
|
|
|
|
{ TCRAccess }
|
|
|
|
{$IFDEF LINUX}
|
|
function GetTickCount: Cardinal;
|
|
var
|
|
tv: timeval;
|
|
begin
|
|
gettimeofday(tv, nil);
|
|
{$RANGECHECKS OFF}
|
|
Result := int64(tv.tv_sec) * 1000 + tv.tv_usec div 1000;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function GenerateTableName(const FieldDesc: TFieldDesc): string;
|
|
begin
|
|
if TCRFieldDesc(FieldDesc).TableInfo <> nil then
|
|
Result := TCRFieldDesc(FieldDesc).TableInfo.TableName
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
{ EFailOver }
|
|
|
|
constructor EFailOver.Create(ConnLostCause: TConnLostCause);
|
|
begin
|
|
FConnLostCause := ConnLostCause;
|
|
inherited Create('');
|
|
end;
|
|
|
|
{ TCRConnection }
|
|
|
|
constructor TCRConnection.Create;
|
|
begin
|
|
inherited;
|
|
|
|
FConnected:= False;
|
|
FIsValid := True;
|
|
end;
|
|
|
|
destructor TCRConnection.Destroy;
|
|
begin
|
|
Disconnect;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCRConnection.Connect(const ConnectString: string);
|
|
begin
|
|
FConnectionTime := GetTickCount;
|
|
FIsValid := True;
|
|
end;
|
|
|
|
procedure TCRConnection.DoError(E: Exception; var Fail: boolean);
|
|
var
|
|
Reconnect: boolean;
|
|
Attempt: Integer;
|
|
{$IFNDEF LITE}
|
|
Reexecute: boolean;
|
|
ConnLostCause: TConnLostCause;
|
|
{$ENDIF}
|
|
begin
|
|
Attempt := 0;
|
|
while not FInProcessError do begin
|
|
Reconnect := Attempt > 0;
|
|
{$IFNDEF LITE}
|
|
Reexecute := False;
|
|
{$ENDIF}
|
|
if Assigned(OnError) then begin
|
|
FInProcessError := True;
|
|
try
|
|
OnError(E, Fail, Reconnect{$IFNDEF LITE}, Reexecute, Attempt, ConnLostCause{$ENDIF});
|
|
finally
|
|
FInProcessError := False;
|
|
end;
|
|
end;
|
|
|
|
if Reconnect then begin
|
|
FReconnected := False;
|
|
try
|
|
FInProcessError := True;
|
|
if Attempt = 0 then
|
|
Disconnect;
|
|
except // don't raise exception
|
|
end;
|
|
try
|
|
Connect('');
|
|
FReconnected := True;
|
|
OnReconnectSuccess;
|
|
except // don't raise exception
|
|
end;
|
|
FInProcessError := False;
|
|
|
|
{$IFNDEF LITE}
|
|
if FReconnected and Reexecute then
|
|
raise EFailOver.Create(ConnLostCause); //Failover
|
|
{$ENDIF}
|
|
|
|
inc(Attempt);
|
|
end;
|
|
|
|
if not Reconnect and (Attempt > 0) then
|
|
if not FReconnected and Assigned(OnReconnectError) then begin
|
|
FInProcessError := True;
|
|
FConnected := True; // to bypass "Value <> GetConnected" check in TCustomDAConnection.SetConnected
|
|
try
|
|
OnReconnectError;
|
|
except // don't raise exception
|
|
end;
|
|
FConnected := False;
|
|
FInProcessError := False;
|
|
end;
|
|
|
|
if not Reconnect or FReconnected then
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TCRConnection.GetConnected: boolean;
|
|
begin
|
|
Result := FConnected;
|
|
end;
|
|
|
|
procedure TCRConnection.SetConnected(Value: boolean);
|
|
begin
|
|
if Value then
|
|
Connect('')
|
|
else
|
|
Disconnect;
|
|
end;
|
|
|
|
procedure TCRConnection.SetUsername(const Value: string);
|
|
begin
|
|
FUsername := Value;
|
|
end;
|
|
|
|
procedure TCRConnection.SetPassword(const Value: string);
|
|
begin
|
|
FPassword := Value;
|
|
end;
|
|
|
|
procedure TCRConnection.SetServer(const Value: string);
|
|
begin
|
|
FServer := Value;
|
|
end;
|
|
|
|
{$IFNDEF LITE}
|
|
procedure TCRConnection.ReturnToPool;
|
|
begin
|
|
Assert(FPool <> nil);
|
|
FOnError := nil;
|
|
Component := nil;
|
|
TCRConnectionPool(FPool).PutConnection(Self);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TCRConnection.SetProp(Prop: integer; const Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prAutoCommit:
|
|
FAutoCommit := Value;
|
|
prConvertEOL:
|
|
FConvertEOL := Value;
|
|
prDisconnectedMode:
|
|
FDisconnectedMode := Boolean(Value);
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TCRConnection.GetProp(Prop: integer; var Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prUsername: // used in Oracle dbExpress driver (TOraSQLMetaData.getProcedureParams)
|
|
// to detect if schema name need to be included in procedure name
|
|
Value := FUsername;
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{ TCRCommand }
|
|
|
|
constructor TCRCommand.Create;
|
|
begin
|
|
inherited;
|
|
|
|
FParams:= TParamDescs.Create;
|
|
end;
|
|
|
|
destructor TCRCommand.Destroy;
|
|
begin
|
|
FParams.Free;
|
|
end;
|
|
|
|
procedure TCRCommand.Prepare;
|
|
begin
|
|
SetCursorState(csPrepared);
|
|
end;
|
|
|
|
procedure TCRCommand.Unprepare;
|
|
begin
|
|
SetCursorState(csInactive);
|
|
end;
|
|
|
|
procedure TCRCommand.SetConnection(Value: TCRConnection);
|
|
begin
|
|
FConnection := Value;
|
|
end;
|
|
|
|
procedure TCRCommand.SetSQL(const Value: string);
|
|
begin
|
|
FSQL := Value;
|
|
end;
|
|
|
|
{function TCRCommand.GetSQL: PChar;
|
|
begin
|
|
Result := PChar(FSQL);
|
|
end;}
|
|
|
|
{ Params }
|
|
|
|
function TCRCommand.GetParamDescType: TParamDescClass;
|
|
begin
|
|
Result := TParamDesc;
|
|
end;
|
|
|
|
procedure TCRCommand.ClearParams;
|
|
begin
|
|
FParams.Clear;
|
|
end;
|
|
|
|
function TCRCommand.AddParam: TParamDesc;
|
|
begin
|
|
Result := TParamDesc.Create;
|
|
FParams.Add(Result);
|
|
end;
|
|
|
|
procedure TCRCommand.DeleteParam(Index: integer);
|
|
begin
|
|
TParamDesc(FParams[Index]).Free;
|
|
FParams.Delete(Index);
|
|
end;
|
|
|
|
function TCRCommand.GetParamCount: integer;
|
|
begin
|
|
Result := FParams.Count;
|
|
end;
|
|
|
|
function TCRCommand.GetParam(Index: integer): TParamDesc;
|
|
begin
|
|
Result := FParams[Index];
|
|
end;
|
|
|
|
function TCRCommand.FindParam(Name: string): TParamDesc;
|
|
begin
|
|
Result := FParams.FindParam(Name);
|
|
end;
|
|
|
|
function TCRCommand.SetProp(Prop: integer; const Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prAutoCommit:
|
|
FAutoCommit := Value;
|
|
prDisableParamScan:; // Used for ODAC
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TCRCommand.GetProp(Prop: integer; var Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prScanParams:
|
|
Value := False;
|
|
prExecuting:
|
|
Value := FExecuting;
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{ $IFNDEF LITE}
|
|
{ TCRTableInfo }
|
|
|
|
constructor TCRTableInfo.Create(Owner: TCRTablesInfo);
|
|
begin
|
|
inherited Create;
|
|
FOwner := Owner;
|
|
FIndex := -1;
|
|
end;
|
|
|
|
procedure TCRTableInfo.SetTableName(Value: string);
|
|
begin
|
|
FTableName := Value;
|
|
if FOwner <> nil then
|
|
FOwner.TableNameChanged;
|
|
end;
|
|
|
|
procedure TCRTableInfo.SetTableAlias(Value: string);
|
|
begin
|
|
FTableAlias := Value;
|
|
if FOwner <> nil then
|
|
FOwner.TableAliasChanged;
|
|
end;
|
|
|
|
function TCRTableInfo.GetTableNameFull: string;
|
|
begin
|
|
Result := FTableName;
|
|
end;
|
|
|
|
procedure TCRTableInfo.SetTableNameFull(Value: string);
|
|
begin
|
|
end;
|
|
|
|
class function TCRTableInfo.IsQuoted(const Value: string): boolean;
|
|
var
|
|
l: integer;
|
|
begin
|
|
l := Length(Value);
|
|
if (l <= 1) then
|
|
Result := False
|
|
else
|
|
Result := (Value[1] = LeftQuote) and (Value[l] = RightQuote);
|
|
end;
|
|
|
|
class function TCRTableInfo.Quote(const Value: string; const LeftQ: char; const RightQ: char): string;
|
|
begin
|
|
if not IsQuoted(Value) then
|
|
Result := LeftQ + Value + RightQ
|
|
else
|
|
Result := Value;
|
|
end;
|
|
|
|
class function TCRTableInfo.UnQuote(const Value: string): string;
|
|
begin
|
|
if IsQuoted(Value) then
|
|
Result := Copy(Value, 2, length(Value) - 2)
|
|
else
|
|
Result := Value;
|
|
end;
|
|
|
|
class function TCRTableInfo.QuotesNeeded(Value: string): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Value := UnQuote(Value);
|
|
Result := False;
|
|
for i := 1 to Length(Value) do
|
|
case Value[i] of
|
|
'a'..'z', 'A'..'Z', '_', '0'..'9':;
|
|
else
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
class function TCRTableInfo.LeftQuote: Char;
|
|
begin
|
|
Result := Char('"');
|
|
end;
|
|
|
|
class function TCRTableInfo.RightQuote: Char;
|
|
begin
|
|
Result := Char('"');
|
|
end;
|
|
|
|
class function TCRTableInfo.NormalizeName(Value: string; const QuoteNames: boolean = False): string;
|
|
begin
|
|
Result := NormalizeName(Value, LeftQuote, RightQuote, QuoteNames);
|
|
end;
|
|
|
|
class function TCRTableInfo.NormalizeName(Value: string; const LeftQ: char; const RightQ: char; const QuoteNames: boolean = False): string;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if Value = '' then begin
|
|
Result := '';
|
|
Exit;
|
|
end;
|
|
|
|
i := Pos('.', Value);
|
|
if i <> 0 then
|
|
Result := NormalizeName(Copy(Value, 1, i - 1), QuoteNames) + '.' + NormalizeName(Copy(Value, i + 1, Length(Value) - i), QuoteNames)
|
|
else
|
|
if QuoteNames or QuotesNeeded(Value) then
|
|
Result := Quote(Value, LeftQ, RightQ)
|
|
else
|
|
Result := UnQuote(Value);
|
|
end;
|
|
|
|
{ TCRTablesInfo }
|
|
|
|
constructor TCRTablesInfo.Create(TableInfoClass: TTableInfoClass);
|
|
begin
|
|
inherited Create;
|
|
FTableInfoClass := TableInfoClass;
|
|
FTableNameList := TStringList.Create;
|
|
FTableAliasList := TStringList.Create;
|
|
{$IFDEF VER6P}
|
|
// Just in case
|
|
FTableNameList.CaseSensitive := False;
|
|
FTableAliasList.CaseSensitive := False;
|
|
{$ENDIF}
|
|
FUpdateCount := 0;
|
|
end;
|
|
|
|
destructor TCRTablesInfo.Destroy;
|
|
begin
|
|
Clear;
|
|
FTableNameList.Free;
|
|
FTableAliasList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TCRTablesInfo.InternalAdd(TableInfo: TCRTableInfo);
|
|
var
|
|
c: integer;
|
|
begin
|
|
c := Count;
|
|
SetLength(FList, c + 1);
|
|
FList[c] := TableInfo;
|
|
TableInfo.Index := c;
|
|
end;
|
|
|
|
function TCRTablesInfo.Add: TCRTableInfo;
|
|
begin
|
|
Result := FTableInfoClass.Create(Self);
|
|
InternalAdd(Result);
|
|
end;
|
|
|
|
procedure TCRTablesInfo.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Count > 0 then begin
|
|
for i := 0 to Count - 1 do
|
|
FList[i].Free;
|
|
SetLength(FList, 0);
|
|
Changed;
|
|
FIsNormalized := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRTablesInfo.Changed;
|
|
begin
|
|
TableNameChanged;
|
|
TableAliasChanged;
|
|
end;
|
|
|
|
procedure TCRTablesInfo.TableNameChanged;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FUpdateCount = 0 then begin
|
|
FTableNameList.Clear;
|
|
for i := 0 to Count - 1 do
|
|
FTableNameList.AddObject(FList[i].TableName, FList[i]);
|
|
FTableNameList.Sort;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRTablesInfo.TableAliasChanged;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FUpdateCount = 0 then begin
|
|
FTableAliasList.Clear;
|
|
for i := 0 to Count - 1 do
|
|
FTableAliasList.AddObject(FList[i].TableAlias, FList[i]);
|
|
FTableAliasList.Sort;
|
|
end;
|
|
end;
|
|
|
|
function TCRTablesInfo.GetCount: Integer;
|
|
begin
|
|
Result := Length(FList);
|
|
end;
|
|
|
|
procedure TCRTablesInfo.BeginUpdate;
|
|
begin
|
|
Inc(FUpdateCount);
|
|
end;
|
|
|
|
procedure TCRTablesInfo.EndUpdate;
|
|
begin
|
|
Dec(FUpdateCount);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TCRTablesInfo.Normalize;
|
|
var
|
|
i: integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
for i := 0 to Count - 1 do begin
|
|
FList[i].TableName := TableInfoClass.NormalizeName(FList[i].TableName);
|
|
FList[i].TableAlias := TableInfoClass.NormalizeName(FList[i].TableAlias);
|
|
FList[i].TableNameFull := TableInfoClass.NormalizeName(FList[i].TableNameFull);
|
|
end;
|
|
FIsNormalized := True;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCRTablesInfo.FindByName(TableName: string): TCRTableInfo;
|
|
var
|
|
Index: integer;
|
|
begin
|
|
Index := IndexByName(TableName);
|
|
if Index = -1 then
|
|
Result := nil
|
|
else
|
|
Result := FList[Index];
|
|
end;
|
|
|
|
function TCRTablesInfo.IndexOf(TableInfo: TCRTableInfo): Integer;
|
|
begin
|
|
Result := 0;
|
|
while (Result < Count) and (FList[Result] <> TableInfo) do
|
|
Inc(Result);
|
|
if Result = Count then
|
|
Result := -1;
|
|
end;
|
|
|
|
function TCRTablesInfo.IndexByName(TableName: string): Integer;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if FIsNormalized then
|
|
TableName := TableInfoClass.NormalizeName(TableName);
|
|
if FUpdateCount = 0 then begin
|
|
Result := FTableNameList.IndexOf(TableName);
|
|
if Result <> -1 then
|
|
Result := TCRTableInfo(FTableNameList.Objects[Result]).Index;
|
|
end
|
|
else
|
|
begin
|
|
Result := -1;
|
|
for i := 0 to Count - 1 do
|
|
if AnsiSameText(FList[i].TableName, TableName) then begin
|
|
Result := i;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCRTablesInfo.IndexByAlias(TableAlias: string): Integer;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if FIsNormalized then
|
|
TableAlias := TableInfoClass.NormalizeName(TableAlias);
|
|
if FUpdateCount = 0 then begin
|
|
Result := FTableAliasList.IndexOf(TableAlias);
|
|
if Result <> -1 then
|
|
Result := TCRTableInfo(FTableAliasList.Objects[Result]).Index;
|
|
end
|
|
else
|
|
begin
|
|
Result := -1;
|
|
for i := 0 to Count - 1 do
|
|
if AnsiSameText(FList[i].TableAlias, TableAlias) then begin
|
|
Result := i;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCRTablesInfo.GetItem(Index: Integer): TCRTableInfo;
|
|
begin
|
|
if (Index < 0) or (Index >= Count) then
|
|
raise Exception.CreateFmt(SListIndexError, [Index]);
|
|
|
|
Result := FList[Index];
|
|
end;
|
|
|
|
procedure TCRTablesInfo.SetItem(Index: Integer; const Value: TCRTableInfo);
|
|
begin
|
|
if (Index >= 0) and (Index < Count) then
|
|
if Value <> FList[Index] then
|
|
FList[Index] := Value;
|
|
end;
|
|
|
|
{ TCRFieldDesc }
|
|
|
|
function TCRFieldDesc.ActualNameQuoted(RecordSet: TCRRecordSet; const QuoteNames: boolean): string;
|
|
begin
|
|
if FActualNameQuoted[QuoteNames] <> '' then
|
|
Result := FActualNameQuoted[QuoteNames]
|
|
else
|
|
begin
|
|
if FTableInfo <> nil then begin
|
|
Result := FTableInfo.NormalizeName(ActualName, QuoteNames);
|
|
FActualNameQuoted[QuoteNames] := Result;
|
|
end
|
|
else begin
|
|
Result := RecordSet.GetTableInfoClass.NormalizeName(ActualName, QuoteNames);
|
|
FActualNameQuoted[QuoteNames] := Result;
|
|
end;
|
|
end;
|
|
end;
|
|
{ $ENDIF}
|
|
|
|
{ TCRRecordSet }
|
|
|
|
constructor TCRRecordSet.Create;
|
|
begin
|
|
inherited;
|
|
|
|
FAfterExecFetch := nil;
|
|
FAfterFetchAll := nil;
|
|
|
|
FTablesInfo := TCRTablesInfo.Create(GetTableInfoClass);
|
|
CreateCommand;
|
|
|
|
FLongStrings := True;
|
|
FFlatBuffers := True;
|
|
end;
|
|
|
|
destructor TCRRecordSet.Destroy;
|
|
begin
|
|
FreeCommand;
|
|
|
|
{ $IFNDEF LITE}
|
|
FTablesInfo.Free;
|
|
{ $ENDIF}
|
|
|
|
inherited;
|
|
end;
|
|
|
|
{procedure TCRRecordSet.CreateCommand;
|
|
begin
|
|
SetCommand(nil);
|
|
end;}
|
|
|
|
procedure TCRRecordSet.FreeCommand;
|
|
begin
|
|
FCommand.Free;
|
|
SetCommand(nil);
|
|
end;
|
|
|
|
procedure TCRRecordSet.SetCommand(Value: TCRCommand);
|
|
begin
|
|
FCommand := Value;
|
|
end;
|
|
|
|
function TCRRecordSet.CanFetchBack: boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
{ Open/Close }
|
|
|
|
procedure TCRRecordSet.InternalPrepare;
|
|
begin
|
|
FCommand.Prepare;
|
|
end;
|
|
|
|
procedure TCRRecordSet.InternalUnPrepare;
|
|
begin
|
|
FCommand.UnPrepare;
|
|
end;
|
|
|
|
procedure TCRRecordSet.InternalOpen;
|
|
begin
|
|
try
|
|
inherited;
|
|
|
|
FEOF := False;
|
|
|
|
ExecFetch;
|
|
except
|
|
if not Prepared then
|
|
InternalUnprepare;
|
|
|
|
if FCommand.GetCursorState = csExecuted then
|
|
FCommand.SetCursorState(csInactive);
|
|
|
|
raise;
|
|
end
|
|
end;
|
|
|
|
procedure TCRRecordSet.Prepare;
|
|
begin
|
|
if not Prepared then begin
|
|
|
|
inherited;
|
|
|
|
if CommandType = ctCursor then
|
|
try
|
|
InitFields;
|
|
Prepared := True;
|
|
except
|
|
Prepared := False;
|
|
InternalUnPrepare;
|
|
raise;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.Unprepare;
|
|
begin
|
|
try
|
|
inherited;
|
|
finally
|
|
{ $IFNDEF LITE}
|
|
FTablesInfo.Clear;
|
|
{ $ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.Disconnect;
|
|
begin
|
|
InternalUnprepare; //Remove all links to DB but not close Data
|
|
Prepared := False; //Set recordset unprepared in case of disconnect mode and
|
|
//explicit disconnection this will prevent from wrong Prepare state
|
|
end;
|
|
|
|
procedure TCRRecordSet.Open;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCRRecordSet.Close;
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCRRecordSet.ExecCommand;
|
|
begin
|
|
FCommand.Execute;
|
|
FWaitForFetchBreak := False;
|
|
end;
|
|
|
|
function TCRRecordSet.NeedInitFields: boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TCRRecordSet.ExecFetch;
|
|
var
|
|
OldCommandType: TCommandType;
|
|
begin
|
|
OldCommandType := CommandType;
|
|
|
|
ExecCommand;
|
|
|
|
if (OldCommandType <> ctCursor) or NeedInitFields then
|
|
InitFields;
|
|
|
|
if FFetchAll then
|
|
FetchAll
|
|
else
|
|
Fetch;
|
|
end;
|
|
|
|
procedure TCRRecordSet.BreakFetch; // Breaks fetch. Can be called from other thread or in non-blocking mode
|
|
begin
|
|
FWaitForFetchBreak := True;
|
|
end;
|
|
|
|
procedure TCRRecordSet.DoBeforeFetch(out Cancel: boolean);
|
|
begin
|
|
Cancel := FWaitForFetchBreak;
|
|
|
|
if Assigned(FOnBeforeFetch) then
|
|
FOnBeforeFetch(Cancel);
|
|
|
|
if Cancel then begin
|
|
// reset cursor state for FetchAll
|
|
if (FCommand.GetCursorState = csFetchingAll) then
|
|
FCommand.SetCursorState(csFetching);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.DoAfterFetch;
|
|
begin
|
|
if Assigned(FOnAfterFetch) then
|
|
FOnAfterFetch;
|
|
end;
|
|
|
|
procedure TCRRecordSet.SortItems;
|
|
begin
|
|
if IndexFields.Count = 0 then
|
|
Exit;
|
|
FetchAll;
|
|
|
|
inherited SortItems;
|
|
end;
|
|
|
|
{ Fields }
|
|
function TCRRecordSet.GetFieldDescType: TFieldDescClass;
|
|
begin
|
|
Result := TCRFieldDesc;
|
|
end;
|
|
|
|
function TCRRecordSet.NeedConvertEOL: boolean;
|
|
begin
|
|
if (FCommand = nil) or (FCommand.FConnection = nil) then
|
|
Result := False
|
|
else
|
|
Result := FCommand.FConnection.FConvertEOL;
|
|
end;
|
|
|
|
{ Records }
|
|
|
|
procedure TCRRecordSet.GetNextRecord(RecBuf: IntPtr);
|
|
var
|
|
Found: boolean;
|
|
Item: PItemHeader;
|
|
begin
|
|
if not EOF then begin
|
|
if IntPtr(FirstItem) = nil then begin
|
|
if not Fetch then begin
|
|
FEOF := True;
|
|
Exit;
|
|
end
|
|
else
|
|
CurrentItem := FirstItem;
|
|
end
|
|
else
|
|
if IntPtr(CurrentItem) = nil then
|
|
CurrentItem := FirstItem
|
|
else
|
|
CurrentItem := CurrentItem.Next;
|
|
|
|
repeat
|
|
if IntPtr(CurrentItem) = nil then begin
|
|
Item := LastItem;
|
|
|
|
if not Fetch then begin
|
|
FEOF := True;
|
|
Exit;
|
|
end
|
|
else begin
|
|
if FUniDirectional or CanFetchBack then begin
|
|
FirstItem.Prev := nil; // remove cycle link
|
|
LastItem.Next := nil;
|
|
end;
|
|
if (IntPtr(Item.Next) = nil) or FUniDirectional then
|
|
CurrentItem := FirstItem
|
|
else
|
|
CurrentItem := Item.Next;
|
|
end
|
|
end;
|
|
|
|
Found := not OmitRecord(CurrentItem);
|
|
if not Found then
|
|
CurrentItem := CurrentItem.Next;
|
|
until Found;
|
|
|
|
FBOF := False;
|
|
FEOF := False;
|
|
if RecBuf <> nil then
|
|
GetRecord(RecBuf);
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.GetPriorRecord(RecBuf: IntPtr);
|
|
var
|
|
Found: boolean;
|
|
Item: PItemHeader;
|
|
begin
|
|
if FUniDirectional then begin
|
|
FBOF := True;
|
|
CurrentItem := nil;
|
|
end
|
|
else
|
|
if not CanFetchBack then
|
|
inherited
|
|
else
|
|
if not BOF then begin
|
|
if IntPtr(LastItem) = nil then begin
|
|
if not Fetch(True){FetchBack!} then begin
|
|
FBOF := True;
|
|
Exit;
|
|
end
|
|
else
|
|
CurrentItem := LastItem;
|
|
end
|
|
else
|
|
if IntPtr(CurrentItem) = nil then
|
|
CurrentItem := LastItem
|
|
else
|
|
CurrentItem := CurrentItem.Prev;
|
|
|
|
repeat
|
|
if IntPtr(CurrentItem) = nil then begin
|
|
Item := FirstItem;
|
|
|
|
if not Fetch(True){FetchBack!} then begin
|
|
FBOF := True;
|
|
Exit;
|
|
end
|
|
else begin
|
|
FirstItem.Prev := nil; // remove cycle link
|
|
LastItem.Next := nil;
|
|
if IntPtr(Item.Prev) = nil then
|
|
CurrentItem := LastItem
|
|
else
|
|
CurrentItem := Item.Prev;
|
|
end;
|
|
end;
|
|
|
|
Found := not OmitRecord(CurrentItem);
|
|
if not Found then
|
|
CurrentItem := CurrentItem.Prev;
|
|
until Found;
|
|
|
|
FBOF := False;
|
|
FEOF := False;
|
|
if RecBuf <> nil then
|
|
GetRecord(RecBuf);
|
|
end;
|
|
end;
|
|
|
|
{ Fetch }
|
|
|
|
procedure TCRRecordSet.FetchAll;
|
|
begin
|
|
while Fetch do;
|
|
end;
|
|
|
|
function TCRRecordSet.CanDisconnect: boolean;
|
|
var
|
|
CursorState: TCursorState;
|
|
begin
|
|
Assert(FCommand <> nil);
|
|
CursorState := FCommand.GetCursorState;
|
|
Result := (CursorState = csInactive) or (CursorState = csFetched);
|
|
end;
|
|
|
|
function TCRRecordSet.RowsReturn: boolean;
|
|
begin
|
|
Result := (CommandType = ctCursor);
|
|
end;
|
|
|
|
function TCRRecordSet.GetCommand: TCRCommand;
|
|
begin
|
|
Result := FCommand;
|
|
end;
|
|
|
|
procedure TCRRecordSet.SetConnection(Value: TCRConnection);
|
|
begin
|
|
FCommand.SetConnection(Value);
|
|
end;
|
|
|
|
procedure TCRRecordSet.SetSQL(const Value: string);
|
|
begin
|
|
FCommand.SetSQL(Value);
|
|
end;
|
|
|
|
function TCRRecordSet.SetProp(Prop: integer; const Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prUniDirectional:
|
|
FUniDirectional := Value;
|
|
prFetchRows:
|
|
FFetchRows := Value;
|
|
prFetchAll:
|
|
FFetchAll := Value;
|
|
prLongStrings:
|
|
FLongStrings := Value;
|
|
prFlatBuffers:
|
|
FFlatBuffers := Value;
|
|
prEnableEmptyStrings:
|
|
EnableEmptyStrings := Value;
|
|
prIndexFieldNames:
|
|
SetIndexFieldNames(Value);
|
|
{$IFDEF HAVE_COMPRESS}
|
|
prCompressBlobMode:
|
|
FCommand.FCompressBlob := TCompressBlobMode(Integer(Value));
|
|
{$ENDIF}
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.SetComponent(Value: TObject);
|
|
begin
|
|
FCommand.Component := Value;
|
|
end;
|
|
|
|
function TCRRecordSet.GetComponent: TObject;
|
|
begin
|
|
Result := FCommand.Component;
|
|
end;
|
|
|
|
function TCRRecordSet.GetProp(Prop: integer; var Value: variant): boolean;
|
|
begin
|
|
Result := True;
|
|
case Prop of
|
|
prFetchAll:
|
|
Value := FFetchAll;
|
|
else
|
|
Assert(False, IntToStr(Prop));
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCRRecordSet.FilterUpdated;
|
|
var
|
|
NotFetched: boolean;
|
|
begin
|
|
NotFetched := (RecordCount = 0) and not FEOF;
|
|
inherited FilterUpdated;
|
|
FEOF := FEOF and not NotFetched;
|
|
end;
|
|
|
|
class function TCRRecordSet.GetTableInfoClass: TTableInfoClass;
|
|
begin
|
|
Result := TCRTableInfo;
|
|
end;
|
|
|
|
{ TParamDesc }
|
|
|
|
constructor TParamDesc.Create;
|
|
begin
|
|
inherited;
|
|
|
|
FDataType := dtUnknown;
|
|
end;
|
|
|
|
destructor TParamDesc.Destroy;
|
|
begin
|
|
end;
|
|
|
|
procedure TParamDesc.Clear;
|
|
begin
|
|
FDataType := dtUnknown;
|
|
end;
|
|
|
|
function TParamDesc.GetName: string;
|
|
begin
|
|
Result := FName;
|
|
end;
|
|
|
|
procedure TParamDesc.SetName(Value: string);
|
|
begin
|
|
FName := Value;
|
|
end;
|
|
|
|
function TParamDesc.GetDataType: word;
|
|
begin
|
|
Result := FDataType;
|
|
end;
|
|
|
|
procedure TParamDesc.SetDataType(Value: word);
|
|
begin
|
|
FDataType := Value;
|
|
end;
|
|
|
|
function TParamDesc.GetParamType: TParamDirection;
|
|
begin
|
|
Result := FParamType;
|
|
end;
|
|
|
|
procedure TParamDesc.SetParamType(Value: TParamDirection);
|
|
begin
|
|
FParamType := Value;
|
|
end;
|
|
|
|
function TParamDesc.GetSize: integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
procedure TParamDesc.SetSize(Value: integer);
|
|
begin
|
|
FSize := Value;
|
|
end;
|
|
|
|
function TParamDesc.GetValue: variant;
|
|
begin
|
|
Result := FData;
|
|
end;
|
|
|
|
procedure TParamDesc.SetValue(const Value: variant);
|
|
begin
|
|
{$IFNDEF VER6P}
|
|
if TVarData(Value).VType = varByRef then
|
|
SetObject(TVarData(Value).VPointer)
|
|
else
|
|
{$ENDIF}
|
|
FData := Value;
|
|
FIsNull := VarIsEmpty(FData) or VarIsNull(FData);
|
|
end;
|
|
|
|
function TParamDesc.GetNull: boolean;
|
|
begin
|
|
Result := FIsNull;
|
|
end;
|
|
|
|
function TParamDesc.GetObject: TSharedObject;
|
|
begin
|
|
if VarIsEmpty(FData) or VarIsNull(FData) then
|
|
Result := nil
|
|
else
|
|
begin
|
|
{$IFDEF CLR}
|
|
Assert(FData is TSharedObject);
|
|
Result := TSharedObject(FData);
|
|
{$ELSE}
|
|
Assert(TVarData(FData).VType = varByRef);
|
|
Result := TVarData(FData).VPointer;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TParamDesc.SetObject(Value: TSharedObject);
|
|
begin
|
|
{$IFDEF CLR}
|
|
FData := Variant(Value);
|
|
{$ELSE}
|
|
FData := Unassigned;
|
|
TVarData(FData).VType := varByRef;
|
|
TVarData(FData).VPointer := Value;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TParamDesc.SetNull(const Value: boolean);
|
|
begin
|
|
FIsNull := Value;
|
|
FData := Unassigned;
|
|
end;
|
|
|
|
procedure TParamDesc.SetConvertEOL(const Value: boolean);
|
|
begin
|
|
FConvertEOL := Value;
|
|
end;
|
|
|
|
{ TParamDescs }
|
|
|
|
destructor TParamDescs.Destroy;
|
|
begin
|
|
Clear;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TParamDescs.Clear;
|
|
var
|
|
i:integer;
|
|
begin
|
|
for i:= 0 to Count - 1 do
|
|
if Items[i] <> nil then
|
|
TParamDesc(Items[i]).Free;
|
|
|
|
inherited Clear;
|
|
end;
|
|
|
|
function TParamDescs.FindParam(Name: string): TParamDesc;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := nil;
|
|
|
|
for i := 0 to Count - 1 do
|
|
if (Items[i] <> nil) then
|
|
if AnsiCompareText(TParamDesc(Items[i]).FName, Name) = 0 then begin
|
|
Result := Items[i];
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
function TParamDescs.ParamByName(Name: string): TParamDesc;
|
|
begin
|
|
Result := FindParam(Name);
|
|
|
|
if Result = nil then
|
|
Assert(False);
|
|
//raise Exception.Create(Format(SParamNotFound, [Name]));
|
|
end;
|
|
|
|
function TParamDescs.GetItems(Index: integer): TParamDesc;
|
|
begin
|
|
Result := TParamDesc(inherited Items[Index]);
|
|
end;
|
|
|
|
end.
|