📄 zibsqlquery.pas
字号:
{********************************************************}
{ }
{ Zeos Database Objects }
{ Interbase Query and Table components }
{ }
{ Copyright (c) 1999-2001 Sergey Seroukhov }
{ Copyright (c) 1999-2001 Zeos Development Group }
{ }
{********************************************************}
unit ZIbSqlQuery;
interface
{$R *.dcr}
uses
SysUtils, Windows, DB, Classes, ZDirSql, ZDirIbSql, DbCommon,
ZIbSqlCon, ZIbSqlTr, ZToken, ZLibIbSql, ZSqlExtra, ZQuery,
ZSqlTypes, ZSqlItems, DbTables;
{$IFNDEF LINUX}
{$INCLUDE ..\Zeos.inc}
{$ELSE}
{$INCLUDE ../Zeos.inc}
{$ENDIF}
type
TZIbSqlOption = (ioAutoIncKey);
TZIbSqlOptions = set of TZIbSqlOption;
{ Direct Interbase dataset with descendant of TZDataSet }
TZCustomIbSqlDataset = class(TZDataSet)
private
FieldDescKey: PFieldDesc;
FExtraOptions: TZIbSqlOptions;
procedure SetDatabase(Value: TZIbSqlDatabase);
procedure SetTransact(Value: TZIbSqlTransact);
function GetDatabase: TZIbSqlDatabase;
function GetTransact: TZIbSqlTransact;
protected
{ Overriding ZDataset methods }
procedure InternalOpen; override;
procedure InternalClose; override;
procedure QueryRecord; override;
procedure UpdateAfterInit(RecordData: PRecordData); override;
{$IFDEF WITH_IPROVIDER}
{ IProvider support }
function PSInTransaction: Boolean; override;
function PSExecuteStatement(const ASql: string; AParams: TParams;
ResultSet: Pointer): Integer; override;
procedure PSSetCommandText(const CommandText: string); override;
{$ENDIF}
public
constructor Create(AOwner: TComponent); override;
procedure AddTableFields(Table: string; SqlFields: TSqlFields); override;
procedure AddTableIndices(Table: string; SqlFields: TSqlFields;
SqlIndices: TSqlIndices); override;
published
property ExtraOptions: TZIbSqlOptions read FExtraOptions write FExtraOptions;
property Database: TZIbSqlDatabase read GetDatabase write SetDatabase;
property Transaction: TZIbSqlTransact read GetTransact write SetTransact;
end;
{ Direct IbSql query with descendant of TDataSet }
TZIbSqlQuery = class(TZCustomIbSqlDataset)
public
property ParamCount;
published
property Params;
property ParamCheck;
property DataSource;
property Sql;
property RequestLive;
property Database;
property Transaction;
property Active;
end;
{ Direct IbSql query with descendant of TDataSet }
TZIbSqlTable = class(TZCustomIbSqlDataset)
private
procedure InternalExecute(Sql: string);
public
{ Extra methods }
procedure AddIndex(const Name, Fields: string; Options: TIndexOptions;
const DescFields: string);
procedure CreateTable(CreateIndexes: Boolean);
procedure DeleteTable;
procedure EmptyTable;
published
property TableName;
property DefaultIndex default False;
property ReadOnly;
property Database;
property Transaction;
property Active;
end;
{ Direct IbSql query with descendant of TDataSet }
TZIbSqlStoredProc = class(TZCustomIbSqlDataset)
private
FPrepared: Boolean;
FIsSelectProc: Boolean;
FProcName: string;
procedure SetProcName(Value: string);
procedure Prepare;
procedure FetchDataIntoOutputParams;
function GetIsSelectProc: Boolean;
function GetParams: TParams;
protected
procedure InternalOpen; override;
{$IFDEF WITH_IPROVIDER}
{ IProvider support }
function PSGetTableName: string;
procedure PSExecute; override;
{$ENDIF}
public
constructor Create(AOwner: TComponent); override;
procedure ExecProc;
property ParamCount;
published
property Params read GetParams;
property DataSource;
property Database;
property Transaction;
property StoredProcName: string read FProcName write SetProcName;
property Active;
end;
implementation
uses ZExtra, ZDBaseConst, ZBlobStream, Math;
{********** TZCustomIbSqlDataset implementation **********}
{ Class constructor }
constructor TZCustomIbSqlDataset.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Query := TDirIbSqlQuery.Create(nil, nil);
DatabaseType := dtInterbase;
FExtraOptions := [];
end;
{ Set connect to database component }
procedure TZCustomIbSqlDataset.SetDatabase(Value: TZIbSqlDatabase);
begin
inherited SetDatabase(Value);
end;
{ Set connect to transact-server component }
procedure TZCustomIbSqlDataset.SetTransact(Value: TZIbSqlTransact);
begin
inherited SetTransact(Value);
end;
{ Get connect to database component }
function TZCustomIbSqlDataset.GetDatabase: TZIbSqlDatabase;
begin
Result := TZIbSqlDatabase(DatabaseObj);
end;
{ Get connect to transact-server component }
function TZCustomIbSqlDataset.GetTransact: TZIbSqlTransact;
begin
Result := TZIbSqlTransact(TransactObj);
end;
procedure TZCustomIbSqlDataset.InternalOpen;
function FindPrimaryKey: PFieldDesc;
var
I: Integer;
IndexDesc: PIndexDesc;
begin
Result := nil;
if SqlParser.Tables.Count = 0 then Exit;
{ Find primary key }
IndexDesc := nil;
for I := 0 to SqlBuffer.SqlIndices.Count-1 do
if StrCaseCmp(SqlBuffer.SqlIndices[I].Table, SqlParser.Tables[0])
and (SqlBuffer.SqlIndices[I].KeyType = ktPrimary) then
begin
IndexDesc := SqlBuffer.SqlIndices[I];
Break;
end;
{ Check primary key }
if (IndexDesc = nil) or (IndexDesc.FieldCount <> 1) then Exit;
Result := SqlBuffer.SqlFields.FindByName(SqlParser.Tables[0],
IndexDesc.Fields[0]);
if Result = nil then Exit;
//if Result.FieldType <> ftInteger then
if not (Result.FieldType in [ftSmallint, ftInteger, ftFloat, ftBCD
{$IFNDEF VER100}, ftLargeInt{$ENDIF}]) then
Result := nil;
end;
begin
inherited;
FieldDescKey := FindPrimaryKey;
end;
procedure TZCustomIbSqlDataset.InternalClose;
begin
inherited;
FieldDescKey := nil;
end;
{ Read query from server to internal buffer }
procedure TZCustomIbSqlDataset.QueryRecord;
var
I, Count: Integer;
RecordData: PRecordData;
FieldDesc: PFieldDesc;
TempStr: string;
TempLong: LongInt;
TempDouble: Double;
TempTime: TDateTime;
TimeStamp: TTimeStamp;
TempDate: TCTimeStructure;
TempPtr: PISC_QUAD;
BlobPtr: PRecordBlob;
Cancel: Boolean;
TempCurrency: System.Currency;
begin
Count := SqlBuffer.Count;
while not Query.EOF and (Count = SqlBuffer.Count) do
begin
{ Go to the record }
if SqlBuffer.FillCount > 0 then
Query.Next;
{ Invoke OnProgress event }
if Assigned(OnProgress) then
begin
Cancel := False;
OnProgress(Self, psRunning, ppFetching, Query.RecNo + 1,
MaxIntValue([Query.RecNo + 1, Query.RecordCount]), Cancel);
if Cancel then Query.Close;
end;
if Query.EOF then Break;
{ Getting record }
RecordData := SqlBuffer.Add;
for I := 0 to SqlBuffer.SqlFields.Count - 1 do
begin
FieldDesc := SqlBuffer.SqlFields[I];
if FieldDesc.FieldNo < 0 then Continue;
if Query.FieldIsNull(FieldDesc.FieldNo) and
not (FieldDesc.FieldType in [ftBlob, ftMemo]) then
Continue;
case FieldDesc.FieldType of
ftString:
begin
case Query.FieldType(FieldDesc.FieldNo) of
SQL_VARYING:
begin
SqlBuffer.SetFieldDataLen(FieldDesc,
Pointer(LongInt(Query.FieldBuffer(FieldDesc.FieldNo)) + 2),
RecordData, Query.FieldSize(FieldDesc.FieldNo));
RecordData.Bytes[FieldDesc.Offset
+ PSmallInt(Query.FieldBuffer(FieldDesc.FieldNo))^ + 1] := 0;
end;
else
begin
TempStr := Query.Field(FieldDesc.FieldNo);
SqlBuffer.SetFieldDataLen(FieldDesc,
PChar(TempStr), RecordData, Length(TempStr));
end;
end;
end;
ftInteger, ftSmallInt:
begin
SqlBuffer.SetFieldData(FieldDesc, Query.FieldBuffer(FieldDesc.FieldNo),
RecordData);
end;
ftFloat:
begin
case Query.FieldType(FieldDesc.FieldNo) of
{$IFNDEF VER100}
SQL_INT64:
TempDouble := PInt64(Query.FieldBuffer(FieldDesc.FieldNo))^
/ IntPower(10, Query.FieldDecimals(FieldDesc.FieldNo));
{$ENDIF}
SQL_LONG {$IFDEF VER100}, SQL_INT64{$ENDIF}:
TempDouble := PLongInt(Query.FieldBuffer(FieldDesc.FieldNo))^
/ IntPower(10, Query.FieldDecimals(FieldDesc.FieldNo));
SQL_DOUBLE:
TempDouble := PDouble(Query.FieldBuffer(FieldDesc.FieldNo))^;
else
TempDouble := PSingle(Query.FieldBuffer(FieldDesc.FieldNo))^;
end;
SqlBuffer.SetFieldData(FieldDesc, @TempDouble, RecordData);
end;
ftDateTime:
begin
isc_decode_date(PISC_QUAD(Query.FieldBuffer(FieldDesc.FieldNo)), @TempDate);
TimeStamp := DateTimeToTimeStamp(EncodeDate(TempDate.tm_year + 1900,
TempDate.tm_mon + 1, TempDate.tm_mday) + EncodeTime(TempDate.tm_hour,
TempDate.tm_min, TempDate.tm_sec, 0));
TempTime := TimeStampToMSecs(TimeStamp);
SqlBuffer.SetFieldData(FieldDesc, @TempTime, RecordData);
end;
ftDate:
begin
isc_decode_sql_date(PISC_DATE(Query.FieldBuffer(FieldDesc.FieldNo)), @TempDate);
TempLong := DateTimeToTimeStamp(EncodeDate(TempDate.tm_year + 1900,
TempDate.tm_mon + 1, TempDate.tm_mday)).Date;
SqlBuffer.SetFieldData(FieldDesc, @TempLong, RecordData);
end;
ftTime:
begin
isc_decode_sql_time(PISC_TIME(Query.FieldBuffer(FieldDesc.FieldNo)), @TempDate);
TempLong := DateTimeToTimeStamp(EncodeTime(TempDate.tm_hour,
TempDate.tm_min, TempDate.tm_sec, 0)).Time;
SqlBuffer.SetFieldData(FieldDesc, @TempLong, RecordData);
end;
ftBCD:
begin
case Query.FieldType(FieldDesc.FieldNo) of
SQL_SHORT:
TempCurrency := PSmallint(Query.FieldBuffer(FieldDesc.FieldNo))^
/ IntPower(10, Query.FieldDecimals(FieldDesc.FieldNo));
SQL_LONG {$IFDEF VER100}, SQL_INT64{$ENDIF}:
TempCurrency := PLongInt(Query.FieldBuffer(FieldDesc.FieldNo))^
/ IntPower(10, Query.FieldDecimals(FieldDesc.FieldNo));
{$IFNDEF VER100}
SQL_INT64:
TempCurrency := PInt64(Query.FieldBuffer(FieldDesc.FieldNo))^
/ IntPower(10, Query.FieldDecimals(FieldDesc.FieldNo));
{$ENDIF}
end;
SqlBuffer.SetFieldData(FieldDesc, @TempCurrency, RecordData);
end;
{$IFNDEF VER100}
ftLargeInt:
begin
SqlBuffer.SetFieldData(FieldDesc, Query.FieldBuffer(FieldDesc.FieldNo),
RecordData);
end;
{$ENDIF}
ftBlob, ftMemo:
begin
{ Initialize blob field }
BlobPtr := PRecordBlob(@RecordData.Bytes[FieldDesc.Offset + 1]);
BlobPtr.BlobType := btExternal;
BlobPtr.Data := nil;
BlobPtr.Size := 0;
TempPtr := PISC_QUAD(Query.FieldBuffer(FieldDesc.FieldNo));
{ Fill not null fields }
if Assigned(TempPtr) then
begin
RecordData.Bytes[FieldDesc.Offset] := 0;
BlobPtr.Handle.Ptr := TempPtr.gds_quad_high;
BlobPtr.Handle.PtrEx := TempPtr.gds_quad_Low;
end
{ Fill null fields }
else
begin
BlobPtr.Handle.Ptr := 0;
BlobPtr.Handle.PtrEx := 0;
end;
end;
//ftArray: todo
else
DatabaseError(SUnknownType + FieldDesc.Alias);
end;
end;
{ Filter received record }
SqlBuffer.FilterItem(SqlBuffer.Count - 1);
end;
end;
{************** Sql-queries processing ******************}
{ Fill collection with fields }
procedure TZCustomIbSqlDataset.AddTableFields(Table: string;
SqlFields: TSqlFields);
var
Size: Integer;
Decimals: Integer;
FieldType: TFieldType;
Query: TDirIbSqlQuery;
Default: string;
BlobType: TBlobType;
SubType: Integer;
FReadOnly: Boolean;
FTypeName, FAlias: string;
begin
Query := TDirIbSqlQuery(Transaction.QueryHandle);
Query.ShowColumns(Table, '');
while not Query.EOF do
begin
{ Evalute field parameters }
Size := StrToIntDef(Query.Field(3), 0);
Decimals := StrToIntDef(Query.Field(6), 0);
SubType := StrToIntDef(Query.Field(7), 0);
FieldType := IbSqlToDelphiType(StrToIntDef(Query.Field(2), 0), SubType, Decimals);
if FieldType in [ftBlob, ftMemo] then BlobType := btExternal
else BlobType := btInternal;
if FieldType = ftBCD then
Size := Decimals
else if FieldType <> ftString then
Size := 0;
Default := Query.Field(5);
StrTok(Default, ' '#9#10#13);
FTypeName := Query.Field(2);
FReadOnly := not Query.FieldIsNull(8);
FAlias := Query.Field(9);
{ Put new field description }
SqlFields.Add(Table, Query.Field(1), FAlias, FTypeName, FieldType, Size, Decimals,
atNone, Query.Field(4) <> '1', FReadOnly, Default, BlobType);
Query.Next;
end;
Query.Close;
end;
{ Fill collection with indices }
procedure TZCustomIbSqlDataset.AddTableIndices(Table: string;
SqlFields: TSqlFields; SqlIndices: TSqlIndices);
var
KeyType: TKeyType;
SortType: TSortType;
Query: TDirIbSqlQuery;
begin
Query := TDirIbSqlQuery(TransactObj.QueryHandle);
Query.ShowIndexes(Table);
while not Query.EOF do
begin
{ Define a key type }
if Query.Field(3) = '1' then
begin
if StrCmpBegin(Query.Field(1),'RDB$PRIMARY') then
KeyType := ktPrimary
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -