27 |
|
{ IBX For Lazarus (Firebird Express) } |
28 |
|
{ Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk } |
29 |
|
{ Portions created by MWA Software are copyright McCallum Whyman } |
30 |
< |
{ Associates Ltd 2011 } |
30 |
> |
{ Associates Ltd 2011 - 2015 } |
31 |
|
{ } |
32 |
|
{************************************************************************} |
33 |
|
|
34 |
|
unit IBCustomDataSet; |
35 |
|
|
36 |
+ |
{$R-} |
37 |
+ |
|
38 |
|
{$Mode Delphi} |
39 |
|
|
40 |
|
{$IFDEF DELPHI} |
51 |
|
{$ENDIF} |
52 |
|
SysUtils, Classes, Forms, Controls, IBDatabase, |
53 |
|
IBExternals, IB, IBHeader, IBSQL, Db, |
54 |
< |
IBUtils, IBBlob; |
54 |
> |
IBUtils, IBBlob, IBSQLParser; |
55 |
|
|
56 |
|
const |
57 |
|
BufferCacheSize = 1000; { Allocate cache in this many record chunks} |
187 |
|
property ApplyOnEvent: TIBGeneratorApplyOnEvent read FApplyOnEvent write FApplyOnEvent; |
188 |
|
end; |
189 |
|
|
190 |
+ |
TIBAutoCommit = (acDisabled, acCommitRetaining); |
191 |
+ |
|
192 |
|
{ TIBCustomDataSet } |
193 |
|
TIBUpdateAction = (uaFail, uaAbort, uaSkip, uaRetry, uaApply, uaApplied); |
194 |
|
|
202 |
|
|
203 |
|
TIBCustomDataSet = class(TDataset) |
204 |
|
private |
205 |
+ |
FAutoCommit: TIBAutoCommit; |
206 |
+ |
FGenerateParamNames: Boolean; |
207 |
|
FGeneratorField: TIBGenerator; |
208 |
|
FNeedsRefresh: Boolean; |
209 |
|
FForcedRefresh: Boolean; |
256 |
|
FBeforeTransactionEnd, |
257 |
|
FAfterTransactionEnd, |
258 |
|
FTransactionFree: TNotifyEvent; |
259 |
< |
|
259 |
> |
FAliasNameMap: array of string; |
260 |
> |
FAliasNameList: array of string; |
261 |
> |
FBaseSQLSelect: TStrings; |
262 |
> |
FParser: TSelectSQLParser; |
263 |
|
function GetSelectStmtHandle: TISC_STMT_HANDLE; |
264 |
|
procedure SetUpdateMode(const Value: TUpdateMode); |
265 |
|
procedure SetUpdateObject(Value: TIBDataSetUpdateObject); |
292 |
|
function GetModifySQL: TStrings; |
293 |
|
function GetTransaction: TIBTransaction; |
294 |
|
function GetTRHandle: PISC_TR_HANDLE; |
295 |
+ |
function GetParser: TSelectSQLParser; |
296 |
|
procedure InternalDeleteRecord(Qry: TIBSQL; Buff: Pointer); virtual; |
297 |
|
function InternalLocate(const KeyFields: string; const KeyValues: Variant; |
298 |
|
Options: TLocateOptions): Boolean; virtual; |
331 |
|
procedure DeactivateTransaction; |
332 |
|
procedure CheckDatasetClosed; |
333 |
|
procedure CheckDatasetOpen; |
334 |
+ |
function CreateParser: TSelectSQLParser; virtual; |
335 |
+ |
procedure FieldDefsFromQuery(SourceQuery: TIBSQL); |
336 |
|
function GetActiveBuf: PChar; |
337 |
|
procedure InternalBatchInput(InputObject: TIBBatchInput); virtual; |
338 |
|
procedure InternalBatchOutput(OutputObject: TIBBatchOutput); virtual; |
365 |
|
procedure ClearCalcFields(Buffer: PChar); override; |
366 |
|
function AllocRecordBuffer: PChar; override; |
367 |
|
procedure DoBeforeDelete; override; |
368 |
+ |
procedure DoAfterDelete; override; |
369 |
|
procedure DoBeforeEdit; override; |
370 |
|
procedure DoBeforeInsert; override; |
371 |
|
procedure DoAfterInsert; override; |
372 |
+ |
procedure DoBeforeOpen; override; |
373 |
|
procedure DoBeforePost; override; |
374 |
+ |
procedure DoAfterPost; override; |
375 |
|
procedure FreeRecordBuffer(var Buffer: PChar); override; |
376 |
|
procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override; |
377 |
|
function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override; |
378 |
|
function GetCanModify: Boolean; override; |
379 |
|
function GetDataSource: TDataSource; override; |
380 |
+ |
function GetDBAliasName(FieldNo: integer): string; |
381 |
+ |
function GetFieldDefFromAlias(aliasName: string): TFieldDef; |
382 |
|
function GetFieldClass(FieldType: TFieldType): TFieldClass; override; |
383 |
|
function GetRecNo: Integer; override; |
384 |
|
function GetRecord(Buffer: PChar; GetMode: TGetMode; |
385 |
|
DoCheck: Boolean): TGetResult; override; |
386 |
|
function GetRecordCount: Integer; override; |
387 |
|
function GetRecordSize: Word; override; |
388 |
+ |
procedure InternalAutoCommit; |
389 |
|
procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override; |
390 |
|
procedure InternalCancel; override; |
391 |
|
procedure InternalClose; override; |
403 |
|
procedure InternalSetFieldData(Field: TField; Buffer: Pointer); virtual; |
404 |
|
procedure InternalSetToRecord(Buffer: PChar); override; |
405 |
|
function IsCursorOpen: Boolean; override; |
406 |
+ |
procedure Loaded; override; |
407 |
|
procedure ReQuery; |
408 |
|
procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override; |
409 |
|
procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override; |
410 |
|
procedure SetCachedUpdates(Value: Boolean); |
411 |
|
procedure SetDataSource(Value: TDataSource); |
412 |
+ |
procedure SetGenerateParamNames(AValue: Boolean); virtual; |
413 |
|
procedure SetFieldData(Field : TField; Buffer : Pointer); override; |
414 |
|
procedure SetFieldData(Field : TField; Buffer : Pointer; |
415 |
|
NativeFormat : Boolean); overload; override; |
417 |
|
|
418 |
|
protected |
419 |
|
{Likely to be made public by descendant classes} |
420 |
+ |
property AutoCommit: TIBAutoCommit read FAutoCommit write FAutoCommit default acDisabled; |
421 |
|
property SQLParams: TIBXSQLDA read GetSQLParams; |
422 |
|
property Params: TIBXSQLDA read GetSQLParams; |
423 |
|
property InternalPrepared: Boolean read FInternalPrepared; |
441 |
|
property ModifySQL: TStrings read GetModifySQL write SetModifySQL; |
442 |
|
property UpdateMode: TUpdateMode read FUpdateMode write SetUpdateMode default upWhereAll; |
443 |
|
property ParamCheck: Boolean read FParamCheck write FParamCheck default True; |
444 |
+ |
property Parser: TSelectSQLParser read GetParser; |
445 |
+ |
property BaseSQLSelect: TStrings read FBaseSQLSelect; |
446 |
|
|
447 |
|
property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect |
448 |
|
write FBeforeDatabaseDisconnect; |
463 |
|
procedure ApplyUpdates; |
464 |
|
function CachedUpdateStatus: TCachedUpdateStatus; |
465 |
|
procedure CancelUpdates; |
466 |
+ |
function GetFieldPosition(AliasName: string): integer; |
467 |
|
procedure FetchAll; |
468 |
|
function LocateNext(const KeyFields: string; const KeyValues: Variant; |
469 |
|
Options: TLocateOptions): Boolean; |
470 |
|
procedure RecordModified(Value: Boolean); |
471 |
|
procedure RevertRecord; |
472 |
|
procedure Undelete; |
473 |
+ |
procedure ResetParser; |
474 |
+ |
function HasParser: boolean; |
475 |
|
|
476 |
|
{ TDataSet support methods } |
477 |
|
function BookmarkValid(Bookmark: TBookmark): Boolean; override; |
482 |
|
function GetFieldData(FieldNo: Integer; Buffer: Pointer): Boolean; overload; (*override;*) |
483 |
|
function GetFieldData(Field : TField; Buffer : Pointer; |
484 |
|
NativeFormat : Boolean) : Boolean; overload; override; |
485 |
+ |
property GenerateParamNames: Boolean read FGenerateParamNames write SetGenerateParamNames; |
486 |
|
function Locate(const KeyFields: string; const KeyValues: Variant; |
487 |
|
Options: TLocateOptions): Boolean; override; |
488 |
|
function Lookup(const KeyFields: string; const KeyValues: Variant; |
534 |
|
write FOnUpdateRecord; |
535 |
|
end; |
536 |
|
|
537 |
< |
TIBDataSet = class(TIBCustomDataSet) |
537 |
> |
TIBParserDataSet = class(TIBCustomDataSet) |
538 |
> |
public |
539 |
> |
property Parser; |
540 |
> |
end; |
541 |
> |
|
542 |
> |
TIBDataSet = class(TIBParserDataSet) |
543 |
|
private |
544 |
|
function GetPrepared: Boolean; |
545 |
|
|
564 |
|
property QModify; |
565 |
|
property StatementType; |
566 |
|
property SelectStmtHandle; |
567 |
+ |
property BaseSQLSelect; |
568 |
|
|
569 |
|
published |
570 |
|
{ TIBCustomDataSet } |
571 |
+ |
property AutoCommit; |
572 |
|
property BufferChunks; |
573 |
|
property CachedUpdates; |
574 |
|
property DeleteSQL; |
577 |
|
property SelectSQL; |
578 |
|
property ModifySQL; |
579 |
|
property GeneratorField; |
580 |
+ |
property GenerateParamNames; |
581 |
|
property ParamCheck; |
582 |
|
property UniDirectional; |
583 |
|
property Filtered; |
894 |
|
FQModify.GoToFirstRecordOnExecute := False; |
895 |
|
FUpdateRecordTypes := [cusUnmodified, cusModified, cusInserted]; |
896 |
|
FParamCheck := True; |
897 |
+ |
FGenerateParamNames := False; |
898 |
|
FForcedRefresh := False; |
899 |
+ |
FAutoCommit:= acDisabled; |
900 |
|
{Bookmark Size is Integer for IBX} |
901 |
|
BookmarkSize := SizeOf(Integer); |
902 |
|
FBase.BeforeDatabaseDisconnect := DoBeforeDatabaseDisconnect; |
910 |
|
else |
911 |
|
if AOwner is TIBTransaction then |
912 |
|
Transaction := TIBTransaction(AOwner); |
913 |
+ |
FBaseSQLSelect := TStringList.Create; |
914 |
|
end; |
915 |
|
|
916 |
|
destructor TIBCustomDataSet.Destroy; |
931 |
|
FOldCacheSize := 0; |
932 |
|
FMappedFieldPosition := nil; |
933 |
|
end; |
934 |
+ |
if assigned(FBaseSQLSelect) then FBaseSQLSelect.Free; |
935 |
+ |
if assigned(FParser) then FParser.Free; |
936 |
|
inherited Destroy; |
937 |
|
end; |
938 |
|
|
1176 |
|
end; |
1177 |
|
end; |
1178 |
|
|
1179 |
+ |
function TIBCustomDataSet.GetFieldPosition(AliasName: string): integer; |
1180 |
+ |
var i: integer; |
1181 |
+ |
Prepared: boolean; |
1182 |
+ |
begin |
1183 |
+ |
Result := 0; |
1184 |
+ |
Prepared := FInternalPrepared; |
1185 |
+ |
if not Prepared then |
1186 |
+ |
InternalPrepare; |
1187 |
+ |
try |
1188 |
+ |
for i := 0 to Length(FAliasNameList) - 1 do |
1189 |
+ |
if FAliasNameList[i] = AliasName then |
1190 |
+ |
begin |
1191 |
+ |
Result := i + 1; |
1192 |
+ |
Exit |
1193 |
+ |
end; |
1194 |
+ |
finally |
1195 |
+ |
if not Prepared then |
1196 |
+ |
InternalUnPrepare; |
1197 |
+ |
end; |
1198 |
+ |
end; |
1199 |
+ |
|
1200 |
|
procedure TIBCustomDataSet.ActivateConnection; |
1201 |
|
begin |
1202 |
|
if not Assigned(Database) then |
1257 |
|
IBError(ibxeDatasetClosed, [nil]); |
1258 |
|
end; |
1259 |
|
|
1260 |
+ |
function TIBCustomDataSet.CreateParser: TSelectSQLParser; |
1261 |
+ |
begin |
1262 |
+ |
Result := TSelectSQLParser.Create(self,FBaseSQLSelect); |
1263 |
+ |
Result.OnSQLChanging := SQLChanging |
1264 |
+ |
end; |
1265 |
+ |
|
1266 |
|
procedure TIBCustomDataSet.CheckNotUniDirectional; |
1267 |
|
begin |
1268 |
|
if UniDirectional then |
1407 |
|
LocalData: Pointer; |
1408 |
|
LocalDate, LocalDouble: Double; |
1409 |
|
LocalInt: Integer; |
1410 |
+ |
LocalBool: wordBool; |
1411 |
|
LocalInt64: Int64; |
1412 |
|
LocalCurrency: Currency; |
1413 |
|
FieldsLoaded: Integer; |
1552 |
|
end; |
1553 |
|
end; |
1554 |
|
end; |
1555 |
+ |
SQL_BOOLEAN: |
1556 |
+ |
begin |
1557 |
+ |
LocalBool:= false; |
1558 |
+ |
rdFields[j].fdDataSize := SizeOf(wordBool); |
1559 |
+ |
if RecordNumber >= 0 then |
1560 |
+ |
LocalBool := Qry.Current[i].AsBoolean; |
1561 |
+ |
LocalData := PChar(@LocalBool); |
1562 |
+ |
end; |
1563 |
|
else { SQL_TEXT, SQL_BLOB, SQL_ARRAY, SQL_QUAD } |
1564 |
|
begin |
1565 |
|
rdFields[j].fdDataSize := Qry.Current[i].Data^.sqllen; |
1835 |
|
ofs: DWORD; |
1836 |
|
Qry: TIBSQL; |
1837 |
|
begin |
1838 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
1838 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
1839 |
> |
SetCursor := False |
1840 |
> |
else |
1841 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
1842 |
|
if SetCursor then |
1843 |
|
Screen.Cursor := crHourGlass; |
1844 |
|
try |
1962 |
|
if FInternalPrepared then |
1963 |
|
Exit; |
1964 |
|
DidActivate := False; |
1965 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
1965 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
1966 |
> |
SetCursor := False |
1967 |
> |
else |
1968 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
1969 |
|
if SetCursor then |
1970 |
|
Screen.Cursor := crHourGlass; |
1971 |
|
try |
1973 |
|
DidActivate := ActivateTransaction; |
1974 |
|
FBase.CheckDatabase; |
1975 |
|
FBase.CheckTransaction; |
1976 |
+ |
if HasParser and (FParser.SQLText <> FQSelect.SQL.Text) then |
1977 |
+ |
FQSelect.SQL.Text := FParser.SQLText; |
1978 |
+ |
// writeln( FQSelect.SQL.Text); |
1979 |
|
if FQSelect.SQL.Text <> '' then |
1980 |
|
begin |
1981 |
|
if not FQSelect.Prepared then |
1982 |
|
begin |
1983 |
+ |
FQSelect.GenerateParamNames := FGenerateParamNames; |
1984 |
|
FQSelect.ParamCheck := ParamCheck; |
1985 |
|
FQSelect.Prepare; |
1986 |
|
end; |
1987 |
+ |
FQDelete.GenerateParamNames := FGenerateParamNames; |
1988 |
|
if (Trim(FQDelete.SQL.Text) <> '') and (not FQDelete.Prepared) then |
1989 |
|
FQDelete.Prepare; |
1990 |
+ |
FQInsert.GenerateParamNames := FGenerateParamNames; |
1991 |
|
if (Trim(FQInsert.SQL.Text) <> '') and (not FQInsert.Prepared) then |
1992 |
|
FQInsert.Prepare; |
1993 |
+ |
FQRefresh.GenerateParamNames := FGenerateParamNames; |
1994 |
|
if (Trim(FQRefresh.SQL.Text) <> '') and (not FQRefresh.Prepared) then |
1995 |
|
FQRefresh.Prepare; |
1996 |
+ |
FQModify.GenerateParamNames := FGenerateParamNames; |
1997 |
|
if (Trim(FQModify.SQL.Text) <> '') and (not FQModify.Prepared) then |
1998 |
|
FQModify.Prepare; |
1999 |
|
FInternalPrepared := True; |
2195 |
|
SQL_TIMESTAMP: |
2196 |
|
Qry.Params[i].AsDateTime := |
2197 |
|
TimeStampToDateTime(MSecsToTimeStamp(trunc(PDouble(data)^))); |
2198 |
+ |
SQL_BOOLEAN: |
2199 |
+ |
Qry.Params[i].AsBoolean := PWordBool(data)^; |
2200 |
|
end; |
2201 |
|
end; |
2202 |
|
end; |
2222 |
|
begin |
2223 |
|
Disconnect; |
2224 |
|
FQSelect.SQL.Assign(Value); |
2225 |
+ |
FBaseSQLSelect.assign(Value); |
2226 |
|
end; |
2227 |
|
end; |
2228 |
|
|
2286 |
|
|
2287 |
|
procedure TIBCustomDataSet.SQLChanging(Sender: TObject); |
2288 |
|
begin |
2289 |
< |
if FOpen then |
2290 |
< |
InternalClose; |
2289 |
> |
Active := false; |
2290 |
> |
{ if FOpen then |
2291 |
> |
InternalClose;} |
2292 |
|
if FInternalPrepared then |
2293 |
|
InternalUnPrepare; |
2294 |
+ |
FieldDefs.Clear; |
2295 |
+ |
FieldDefs.Updated := false; |
2296 |
|
end; |
2297 |
|
|
2298 |
|
{ I can "undelete" uninserted records (make them "inserted" again). |
2550 |
|
inherited DoBeforeDelete; |
2551 |
|
end; |
2552 |
|
|
2553 |
+ |
procedure TIBCustomDataSet.DoAfterDelete; |
2554 |
+ |
begin |
2555 |
+ |
inherited DoAfterDelete; |
2556 |
+ |
InternalAutoCommit; |
2557 |
+ |
end; |
2558 |
+ |
|
2559 |
|
procedure TIBCustomDataSet.DoBeforeEdit; |
2560 |
|
var |
2561 |
|
Buff: PRecordData; |
2584 |
|
inherited DoAfterInsert; |
2585 |
|
end; |
2586 |
|
|
2587 |
+ |
procedure TIBCustomDataSet.DoBeforeOpen; |
2588 |
+ |
begin |
2589 |
+ |
if assigned(FParser) then |
2590 |
+ |
FParser.Reset; |
2591 |
+ |
DataEvent(deCheckBrowseMode,1); {Conventional use to report getting ready to prepare} |
2592 |
+ |
inherited DoBeforeOpen; |
2593 |
+ |
DataEvent(deCheckBrowseMode,2); {Conventional use to report the right time to set parameters} |
2594 |
+ |
end; |
2595 |
+ |
|
2596 |
|
procedure TIBCustomDataSet.DoBeforePost; |
2597 |
|
begin |
2598 |
|
inherited DoBeforePost; |
2601 |
|
GeneratorField.Apply |
2602 |
|
end; |
2603 |
|
|
2604 |
+ |
procedure TIBCustomDataSet.DoAfterPost; |
2605 |
+ |
begin |
2606 |
+ |
inherited DoAfterPost; |
2607 |
+ |
InternalAutoCommit; |
2608 |
+ |
end; |
2609 |
+ |
|
2610 |
|
procedure TIBCustomDataSet.FetchAll; |
2611 |
|
var |
2612 |
|
SetCursor: Boolean; |
2616 |
|
CurBookmark: string; |
2617 |
|
{$ENDIF} |
2618 |
|
begin |
2619 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
2619 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
2620 |
> |
SetCursor := False |
2621 |
> |
else |
2622 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
2623 |
|
if SetCursor then |
2624 |
|
Screen.Cursor := crHourGlass; |
2625 |
|
try |
2683 |
|
result := FDataLink.DataSource; |
2684 |
|
end; |
2685 |
|
|
2686 |
+ |
function TIBCustomDataSet.GetDBAliasName(FieldNo: integer): string; |
2687 |
+ |
begin |
2688 |
+ |
Result := FAliasNameMap[FieldNo-1] |
2689 |
+ |
end; |
2690 |
+ |
|
2691 |
+ |
function TIBCustomDataSet.GetFieldDefFromAlias(aliasName: string): TFieldDef; |
2692 |
+ |
var |
2693 |
+ |
i: integer; |
2694 |
+ |
begin |
2695 |
+ |
Result := nil; |
2696 |
+ |
for i := 0 to Length(FAliasNameMap) - 1 do |
2697 |
+ |
if FAliasNameMap[i] = aliasName then |
2698 |
+ |
begin |
2699 |
+ |
Result := FieldDefs[i+1]; |
2700 |
+ |
Exit |
2701 |
+ |
end; |
2702 |
+ |
end; |
2703 |
+ |
|
2704 |
|
function TIBCustomDataSet.GetFieldClass(FieldType: TFieldType): TFieldClass; |
2705 |
|
begin |
2706 |
|
Result := DefaultFieldClasses[FieldType]; |
2884 |
|
result := FRecordBufferSize; |
2885 |
|
end; |
2886 |
|
|
2887 |
+ |
procedure TIBCustomDataSet.InternalAutoCommit; |
2888 |
+ |
begin |
2889 |
+ |
with Transaction do |
2890 |
+ |
if InTransaction and (FAutoCommit = acCommitRetaining) then |
2891 |
+ |
begin |
2892 |
+ |
if CachedUpdates then ApplyUpdates; |
2893 |
+ |
CommitRetaining; |
2894 |
+ |
end; |
2895 |
+ |
end; |
2896 |
+ |
|
2897 |
|
procedure TIBCustomDataSet.InternalAddRecord(Buffer: Pointer; Append: Boolean); |
2898 |
|
begin |
2899 |
|
CheckEditState; |
2973 |
|
Buff: PChar; |
2974 |
|
SetCursor: Boolean; |
2975 |
|
begin |
2976 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
2976 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
2977 |
> |
SetCursor := False |
2978 |
> |
else |
2979 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
2980 |
|
if SetCursor then |
2981 |
|
Screen.Cursor := crHourGlass; |
2982 |
|
try |
3024 |
|
end; |
3025 |
|
|
3026 |
|
procedure TIBCustomDataSet.InternalInitFieldDefs; |
3027 |
+ |
begin |
3028 |
+ |
if not InternalPrepared then |
3029 |
+ |
begin |
3030 |
+ |
InternalPrepare; |
3031 |
+ |
exit; |
3032 |
+ |
end; |
3033 |
+ |
FieldDefsFromQuery(FQSelect); |
3034 |
+ |
end; |
3035 |
+ |
|
3036 |
+ |
procedure TIBCustomDataSet.FieldDefsFromQuery(SourceQuery: TIBSQL); |
3037 |
|
const |
3038 |
|
DefaultSQL = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize} |
3039 |
|
'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME ' + {do not localize} |
3047 |
|
FieldSize: Word; |
3048 |
|
FieldNullable : Boolean; |
3049 |
|
i, FieldPosition, FieldPrecision: Integer; |
3050 |
< |
FieldAliasName: string; |
3050 |
> |
FieldAliasName, DBAliasName: string; |
3051 |
|
RelationName, FieldName: string; |
3052 |
|
Query : TIBSQL; |
3053 |
|
FieldIndex: Integer; |
3147 |
|
end; |
3148 |
|
|
3149 |
|
begin |
2989 |
– |
if not InternalPrepared then |
2990 |
– |
begin |
2991 |
– |
InternalPrepare; |
2992 |
– |
exit; |
2993 |
– |
end; |
3150 |
|
FRelationNodes := TRelationNode.Create; |
3151 |
|
FNeedsRefresh := False; |
3152 |
|
Database.InternalTransaction.StartTransaction; |
3157 |
|
FieldDefs.BeginUpdate; |
3158 |
|
FieldDefs.Clear; |
3159 |
|
FieldIndex := 0; |
3160 |
< |
if (Length(FMappedFieldPosition) < FQSelect.Current.Count) then |
3161 |
< |
SetLength(FMappedFieldPosition, FQSelect.Current.Count); |
3160 |
> |
if (Length(FMappedFieldPosition) < SourceQuery.Current.Count) then |
3161 |
> |
SetLength(FMappedFieldPosition, SourceQuery.Current.Count); |
3162 |
|
Query.SQL.Text := DefaultSQL; |
3163 |
|
Query.Prepare; |
3164 |
< |
for i := 0 to FQSelect.Current.Count - 1 do |
3165 |
< |
with FQSelect.Current[i].Data^ do |
3164 |
> |
SetLength(FAliasNameMap, SourceQuery.Current.Count); |
3165 |
> |
SetLength(FAliasNameList, SourceQuery.Current.Count); |
3166 |
> |
for i := 0 to SourceQuery.Current.Count - 1 do |
3167 |
> |
with SourceQuery.Current[i].Data^ do |
3168 |
|
begin |
3169 |
|
{ Get the field name } |
3170 |
< |
SetString(FieldAliasName, aliasname, aliasname_length); |
3170 |
> |
FieldAliasName := SourceQuery.Current[i].Name; |
3171 |
> |
SetString(DBAliasName, aliasname, aliasname_length); |
3172 |
|
SetString(RelationName, relname, relname_length); |
3173 |
|
SetString(FieldName, sqlname, sqlname_length); |
3174 |
+ |
FAliasNameList[i] := DBAliasName; |
3175 |
|
FieldSize := 0; |
3176 |
|
FieldPrecision := 0; |
3177 |
< |
FieldNullable := FQSelect.Current[i].IsNullable; |
3177 |
> |
FieldNullable := SourceQuery.Current[i].IsNullable; |
3178 |
|
case sqltype and not 1 of |
3179 |
|
{ All VARCHAR's must be converted to strings before recording |
3180 |
|
their values } |
3249 |
|
FieldSize := sizeof (TISC_QUAD); |
3250 |
|
FieldType := ftUnknown; |
3251 |
|
end; |
3252 |
+ |
SQL_BOOLEAN: |
3253 |
+ |
FieldType:= ftBoolean; |
3254 |
|
else |
3255 |
|
FieldType := ftUnknown; |
3256 |
|
end; |
3262 |
|
with FieldDefs.AddFieldDef do |
3263 |
|
begin |
3264 |
|
Name := FieldAliasName; |
3265 |
< |
(* FieldNo := FieldPosition;*) |
3265 |
> |
FAliasNameMap[FieldNo-1] := DBAliasName; |
3266 |
|
DataType := FieldType; |
3267 |
|
Size := FieldSize; |
3268 |
|
Precision := FieldPrecision; |
3347 |
|
else case cur_field.DataType of |
3348 |
|
ftString: |
3349 |
|
cur_param.AsString := cur_field.AsString; |
3350 |
< |
ftBoolean, ftSmallint, ftWord: |
3350 |
> |
ftBoolean: |
3351 |
> |
cur_param.AsBoolean := cur_field.AsBoolean; |
3352 |
> |
ftSmallint, ftWord: |
3353 |
|
cur_param.AsShort := cur_field.AsInteger; |
3354 |
|
ftInteger: |
3355 |
|
cur_param.AsLong := cur_field.AsInteger; |
3411 |
|
end; |
3412 |
|
|
3413 |
|
begin |
3414 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3414 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
3415 |
> |
SetCursor := False |
3416 |
> |
else |
3417 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3418 |
|
if SetCursor then |
3419 |
|
Screen.Cursor := crHourGlass; |
3420 |
|
try |
3489 |
|
SetCursor: Boolean; |
3490 |
|
bInserting: Boolean; |
3491 |
|
begin |
3492 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3492 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
3493 |
> |
SetCursor := False |
3494 |
> |
else |
3495 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3496 |
|
if SetCursor then |
3497 |
|
Screen.Cursor := crHourGlass; |
3498 |
|
try |
3553 |
|
result := FOpen; |
3554 |
|
end; |
3555 |
|
|
3556 |
+ |
procedure TIBCustomDataSet.Loaded; |
3557 |
+ |
begin |
3558 |
+ |
if assigned(FQSelect) then |
3559 |
+ |
FBaseSQLSelect.assign(FQSelect.SQL); |
3560 |
+ |
inherited Loaded; |
3561 |
+ |
end; |
3562 |
+ |
|
3563 |
|
function TIBCustomDataSet.Locate(const KeyFields: string; const KeyValues: Variant; |
3564 |
|
Options: TLocateOptions): Boolean; |
3565 |
|
var |
3642 |
|
procedure TIBCustomDataSet.InternalSetFieldData(Field: TField; Buffer: Pointer); |
3643 |
|
var |
3644 |
|
Buff, TmpBuff: PChar; |
3645 |
+ |
MappedFieldPos: integer; |
3646 |
|
begin |
3647 |
|
Buff := GetActiveBuf; |
3648 |
|
if Field.FieldNo < 0 then |
3659 |
|
begin |
3660 |
|
{ If inserting, Adjust record position } |
3661 |
|
AdjustRecordOnInsert(Buff); |
3662 |
< |
if (FMappedFieldPosition[Field.FieldNo - 1] > 0) and |
3663 |
< |
(FMappedFieldPosition[Field.FieldNo - 1] <= rdFieldCount) then |
3662 |
> |
MappedFieldPos := FMappedFieldPosition[Field.FieldNo - 1]; |
3663 |
> |
if (MappedFieldPos > 0) and |
3664 |
> |
(MappedFieldPos <= rdFieldCount) then |
3665 |
|
begin |
3666 |
|
Field.Validate(Buffer); |
3667 |
|
if (Buffer = nil) or |
3668 |
|
(Field is TIBStringField) and (PChar(Buffer)[0] = #0) then |
3669 |
< |
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := True |
3669 |
> |
rdFields[MappedFieldPos].fdIsNull := True |
3670 |
|
else begin |
3671 |
< |
Move(Buffer^, Buff[rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataOfs], |
3672 |
< |
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataSize); |
3673 |
< |
if (rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataType = SQL_TEXT) or |
3674 |
< |
(rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataType = SQL_VARYING) then |
3675 |
< |
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataLength := StrLen(PChar(Buffer)); |
3676 |
< |
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := False; |
3671 |
> |
Move(Buffer^, Buff[rdFields[MappedFieldPos].fdDataOfs], |
3672 |
> |
rdFields[MappedFieldPos].fdDataSize); |
3673 |
> |
if (rdFields[MappedFieldPos].fdDataType = SQL_TEXT) or |
3674 |
> |
(rdFields[MappedFieldPos].fdDataType = SQL_VARYING) then |
3675 |
> |
rdFields[MappedFieldPos].fdDataLength := StrLen(PChar(Buffer)); |
3676 |
> |
rdFields[MappedFieldPos].fdIsNull := False; |
3677 |
|
if rdUpdateStatus = usUnmodified then |
3678 |
|
begin |
3679 |
|
if CachedUpdates then |
3768 |
|
begin |
3769 |
|
CheckDatasetClosed; |
3770 |
|
FieldDefs.Clear; |
3771 |
+ |
FieldDefs.Updated := false; |
3772 |
|
FInternalPrepared := False; |
3773 |
+ |
Setlength(FAliasNameList,0); |
3774 |
|
end; |
3775 |
|
end; |
3776 |
|
|
3780 |
|
SetCursor: Boolean; |
3781 |
|
begin |
3782 |
|
DidActivate := False; |
3783 |
< |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3783 |
> |
if Assigned(Database) and not Database.SQLHourGlass then |
3784 |
> |
SetCursor := False |
3785 |
> |
else |
3786 |
> |
SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault); |
3787 |
|
if SetCursor then |
3788 |
|
Screen.Cursor := crHourGlass; |
3789 |
|
try |
3812 |
|
Result := FQSelect.Handle; |
3813 |
|
end; |
3814 |
|
|
3815 |
+ |
function TIBCustomDataSet.GetParser: TSelectSQLParser; |
3816 |
+ |
begin |
3817 |
+ |
if not assigned(FParser) then |
3818 |
+ |
FParser := CreateParser; |
3819 |
+ |
Result := FParser |
3820 |
+ |
end; |
3821 |
+ |
|
3822 |
+ |
procedure TIBCustomDataSet.ResetParser; |
3823 |
+ |
begin |
3824 |
+ |
if assigned(FParser) then |
3825 |
+ |
begin |
3826 |
+ |
FParser.Free; |
3827 |
+ |
FParser := nil; |
3828 |
+ |
SQLChanging(nil) |
3829 |
+ |
end; |
3830 |
+ |
end; |
3831 |
+ |
|
3832 |
+ |
function TIBCustomDataSet.HasParser: boolean; |
3833 |
+ |
begin |
3834 |
+ |
Result := not (csDesigning in ComponentState) and (FParser <> nil) |
3835 |
+ |
end; |
3836 |
+ |
|
3837 |
+ |
procedure TIBCustomDataSet.SetGenerateParamNames(AValue: Boolean); |
3838 |
+ |
begin |
3839 |
+ |
if FGenerateParamNames = AValue then Exit; |
3840 |
+ |
FGenerateParamNames := AValue; |
3841 |
+ |
Disconnect |
3842 |
+ |
end; |
3843 |
+ |
|
3844 |
|
procedure TIBCustomDataSet.InitRecord(Buffer: PChar); |
3845 |
|
begin |
3846 |
|
inherited InitRecord(Buffer); |