myservicesuni.pas
来自「CrLab UniDAC 1.0 include sources」· PAS 代码 · 共 1,295 行 · 第 1/3 页
PAS
1,295 行
Limit := FLimit;
Result := Result + ' LIMIT ' + IntToStr(FOffset) + ', ' + IntToStr(Limit);
if BatchedHandler then begin
Result := Result + ';';
Result := Result + ' HANDLER ' + QTableName + ' CLOSE';
end;
end;
end;
{ TCustomMyDataSetUpdater }
constructor TCustomMyDataSetUpdater.Create(AOwner: TDataSetService);
begin
inherited;
FDataSetService := TCustomMyDataSetService(AOwner);
end;
function TCustomMyDataSetUpdater.GetIdentityFieldValue(var Value: variant): boolean;
var
v: variant;
id: int64;
begin
Result := False;
BeginConnection;
try
FDataSetService.GetIConnection.GetProp(prLastInsertId, v);
{$IFDEF VER6P}
id := v;
{$ELSE}
id := PInt64(@TVarData(v).VInteger)^;
{$ENDIF}
if id <> 0 then begin
{$IFDEF VER6P}
Value := id;
{$ELSE}
Value := Integer(id); // Int64 not supported if Delphi5 variants
{$ENDIF}
Result := True;
end;
finally
EndConnection;
end;
end;
procedure TCustomMyDataSetUpdater.CheckUpdateQuery(const StatementType: TStatementType);
begin
inherited;
if FUpdateQuery is TCustomDADataSet then begin
TDBAccessUtils.SetFetchAll(TCustomDADataSet(FUpdateQuery), True);
end;
end;
procedure TCustomMyDataSetUpdater.SetUpdateQueryOptions(const StatementType: TStatementType);
var
DestRecordSet, SourceRecordSet: TCRRecordSet;
procedure CopyPropR(Prop: integer);
var
v: variant;
begin
SourceRecordSet.GetProp(Prop, v);
DestRecordSet.SetProp(Prop, v);
end;
begin
SourceRecordSet := GetIRecordSet;
DestRecordSet := TDBAccessUtils.GetIRecordSet(FUpdateQuery as TCustomDADataSet);
CopyPropR(prEnableBoolean);
end;
procedure TCustomMyDataSetUpdater.CheckUpdateSQL(const SQL: string;
const StatementTypes: TStatementTypes; out ParamsInfo: TDAParamsInfo; UseGenerator: boolean = True);
var
Offset, i: integer;
ICommand: TMySQLCommand;
begin
inherited;
if ParamsInfo = nil then
Exit;
if not (((FDataSet.Params.Count > 0) or FDataSetService.IsFullRefresh) and (stRefresh in StatementTypes)) and not (stRefreshQuick in StatementTypes) then begin
if IsClass(FUpdateQuery, TCustomDADataSet) then
ICommand := TDBAccessUtils.GetICommand(TCustomDADataSet(FUpdateQuery)) as TMySQLCommand
else
if IsClass(FUpdateQuery, TCustomDASQL) then
ICommand := TDBAccessUtils.GetICommand(TCustomDASQL(FUpdateQuery)) as TMySQLCommand
else begin
ICommand := nil;
Assert(False);
end;
for i := 0 to ParamsInfo.Count - 1 do begin
Offset := TCustomMySQLGenerator(FDataSetService.SQLGenerator).GetParamOffset(i);
ICommand.SetProp(prParamPosition, Offset);
end;
end;
end;
function TCustomMyDataSetUpdater.IsRefreshQuickField(FieldDesc: TFieldDesc): boolean;
begin
Result := TMySQLFieldDesc(FieldDesc).MySQLType = FIELD_TYPE_TIMESTAMP;
end;
procedure TCustomMyDataSetUpdater.SaveMaxRefreshQuickValue(FieldDesc: TFieldDesc; const Value: variant);
var
Field: TMySQLFieldDesc;
CurrValue: TDateTime;
begin
CurrValue := 0;
if (not VarIsEmpty(Value)) and (not VarIsNull(Value)) then
CurrValue := Value;
Field := TMySQLFieldDesc(GetIRecordSet.FindField(FieldDesc.Name));
if (Field <> nil) and (Field.MySQLType = FIELD_TYPE_TIMESTAMP) and (Field.TableInfo <> nil) then begin
if TMyTableInfo(Field.TableInfo).MaxTimestamp < CurrValue then
TMyTableInfo(Field.TableInfo).MaxTimestamp := CurrValue;
end;
end;
procedure TCustomMyDataSetUpdater.PrepareUpdate;
begin
if roBeforeEdit in FDataSet.RefreshOptions then
PerformRefreshRecord;
inherited;
end;
function TCustomMyDataSetUpdater.PerformLock: boolean;
begin
if not TDBAccessUtils.GetFetchAll(FDataSet) then
DatabaseError(SLockVsFetchAll);
Result := inherited PerformLock;
end;
{ TCustomMyDataSetService }
constructor TCustomMyDataSetService.Create(AOwner: TMemDataSet);
begin
inherited;
FLeftQuote := '`';
FRightQuote := '`';
end;
procedure TCustomMyDataSetService.CreateDataSetUpdater;
begin
SetDataSetUpdater(TCustomMyDataSetUpdater.Create(Self));
end;
procedure TCustomMyDataSetService.SetDataSetUpdater(Value: TDataSetUpdater);
begin
inherited;
FUpdater := TCustomMyDataSetUpdater(Value);
end;
procedure TCustomMyDataSetService.CreateSQLGenerator;
begin
SetSQLGenerator(TCustomMySQLGenerator.Create(Self));
end;
function TCustomMyDataSetService.DetectCanModify: boolean;
begin
Assert(GetIRecordSet <> nil, 'FIRecordSet must be setted to this time');
Result := inherited DetectCanModify or
not (FDataSet.ReadOnly or FDataSet.UniDirectional) and
(FIsAnyFieldCanBeModified or
(FDataSet.SQLInsert.Count > 0) or
(FDataSet.SQLUpdate.Count > 0) or
(FDataSet.SQLDelete.Count > 0));
end;
function TCustomMyDataSetService.CanUseAllKeyFields: boolean;
var
ByTable: boolean;
begin
// upd is this really nec. here
ByTable := False;
if UpdatingTableInfoIdx >= 0 then
{ if Self is TCustomMyTable then
ByTable := True
else}
if not IsFullRefresh then
ByTable := True;
Result := not ByTable;
end;
procedure TCustomMyDataSetService.FillFieldDescs(out FieldDescs: TFieldDescArray;
FillKeyFieldDescs, ForceUseAllFields: boolean);
procedure ProcessField(FieldDesc: TMySQLFieldDesc);
begin
if FillKeyFieldDescs then begin
if FieldDesc.IsKey then begin
SetLength(FieldDescs, Length(FieldDescs) + 1);
FieldDescs[High(FieldDescs)] := FieldDesc;
end;
end
else begin
if not FieldDesc.ReadOnly then begin
SetLength(FieldDescs, Length(FieldDescs) + 1);
FieldDescs[High(FieldDescs)] := FieldDesc;
end;
end;
end;
procedure CheckPrimaryKeys;
var
HasPrimaryKeys: boolean;
i, j: integer;
begin
HasPrimaryKeys := False;
for i := Length(FieldDescs) - 1 downto 0 do begin
HasPrimaryKeys := (FieldDescs[i] as TMySQLFieldDesc).IsPrimaryKey;
if HasPrimaryKeys then
Break;
end;
if HasPrimaryKeys then begin
j := 0;
for i := 0 to Length(FieldDescs) - 1 do begin
if (FieldDescs[i] as TMySQLFieldDesc).IsPrimaryKey then begin
if i <> j then
FieldDescs[j] := FieldDescs[i];
Inc(j);
end;
end;
if Length(FieldDescs) <> j then
SetLength(FieldDescs, j);
end;
end;
var
Field: TField;
FieldDesc: TMySQLFieldDesc;
i: integer;
IsNeedProcessField: boolean;
begin
FieldDescs := nil;
if (FDataSet.Fields.Count = 0) or (GetIRecordSet.Fields.Count = 0) then
Exit;
for i := 0 to FDataSet.Fields.Count - 1 do begin
Field := FDataSet.Fields[i];
if Field.FieldKind = fkData then begin
FieldDesc := FDataSet.GetFieldDesc(Field) as TMySQLFieldDesc;
IsNeedProcessField := ForceUseAllFields or //(Self is TCustomMyTable) or
(FieldDesc.TableInfo = UpdatingTableInfo) or
((FieldDesc.TableInfo = nil) and not FDataSet.Options.SetFieldsReadOnly);
if IsNeedProcessField then
ProcessField(FieldDesc);
end;
end;
if FillKeyFieldDescs then
CheckPrimaryKeys;
end;
procedure TCustomMyDataSetService.FillKeyFieldDescs(out KeyFieldDescs: TFieldDescArray; ForceUseAllKeyFields: boolean);
begin
if (GetKeyFields <> '') or (IdentityField <> nil) then
inherited FillKeyFieldDescs(KeyFieldDescs, ForceUseAllKeyFields)
else
FillFieldDescs(KeyFieldDescs, True, ForceUseAllKeyFields);
end;
procedure TCustomMyDataSetService.FillDataFieldDescs(out DataFieldDescs: TFieldDescArray; ForceUseAllKeyFields: boolean);
begin
FillFieldDescs(DataFieldDescs, False, ForceUseAllKeyFields);
end;
function TCustomMyDataSetService.DetectIdentityField: TField;
var
Field: TField;
FieldDesc: TMySQLFieldDesc;
i: integer;
begin
Result := nil;
/// downto to correct set FIdentityField
for i := 0 to FDataSet.Fields.Count - 1 do begin
Field := FDataSet.Fields[i];
if Field.FieldKind = fkData then begin
FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));
if FieldDesc.IsAutoIncrement then begin
Assert((FUpdatingTableInfoIdx >= - 1) and (FUpdatingTableInfoIdx < GetTablesInfo.Count));
if (FUpdatingTableInfoIdx >= 0) and (FieldDesc.TableInfo <> nil)
and (FieldDesc.TableInfo.TableName = GetTablesInfo[FUpdatingTableInfoIdx].TableName) then begin
Result := Field;
Exit;
end;
end;
end;
end;
end;
procedure TCustomMyDataSetService.CloseCursor;
begin
inherited;
FTimestampField := nil;
end;
procedure TCustomMyDataSetService.InitCursor;
var
Field: TField;
FieldDesc: TMySQLFieldDesc;
i: integer;
begin
inherited;
FTimestampField := nil;
/// downto to correct set FIdentityField
for i := FDataSet.Fields.Count - 1 downto 0 do begin
Field := FDataSet.Fields[i];
if Field.FieldKind = fkData then begin
FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));
if FieldDesc.IsAutoIncrement then begin
if FDataSet.Options.SetFieldsReadOnly then
Field.ReadOnly := True;
Field.AutoGenerateValue := arAutoInc;
end;
if (TMySQLFieldDesc(FieldDesc).MySQLType = FIELD_TYPE_TIMESTAMP) then
FTimestampField := TMySQLFieldDesc(FieldDesc);
end;
end;
end;
procedure TCustomMyDataSetService.FillFieldsOrigin;
var
Field: TField;
FieldDesc: TMySQLFieldDesc;
TableName: string;
i: integer;
begin
for i := FDataSet.Fields.Count - 1 downto 0 do begin
Field := FDataSet.Fields[i];
if Field.FieldKind = fkData then begin
FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));
TableName := GenerateTableName(FieldDesc);
Field.Origin := TableName + '.' + QuoteName(FieldDesc.ActualName);
end;
end;
end;
procedure TCustomMyDataSetService.FillFieldsDefaultValues;
// Must be sync with MyClasses DateTimeFromStr!!!
function DateTimeFromStr(const Def: string; FieldDesc: TMySQLFieldDesc; var Res: TDateTime): boolean;
//var
//Len: integer;
function IntAt(const Off, Len: integer): integer; // return decoded integer from string
var
i: integer;
begin
Result := 0;
for i := 1 + Off to Off + Len do
Result := Result * 10 + (Byte(Def[i]) - $30 {Ord('0')});
end;
function Year2: integer;
begin
Result := IntAt(0, 2);
if Result >= 70 then
Result := 1900 + Result
else
Result := 2000 + Result;
end;
const
HoursPerDay = 24;
var
i: integer;
t: TDateTime;
//s: string;
begin
Result := True;
//Len := Length(Def);
case TMySQLFieldDesc(FieldDesc).MySQLType of
FIELD_TYPE_TIMESTAMP:
case FieldDesc.Length of
19: // YYYY-MM-DD HH:MM:SS
Result := TryEncodeDateTime(IntAt(0, 4), IntAt(5, 2), IntAt(8, 2), IntAt(11, 2), IntAt(14, 2), IntAt(17, 2), 0, Res);
14: // YYYYMMDDHHMMSS
Result := TryEncodeDateTime(IntAt(0, 4), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), IntAt(10, 2), IntAt(12, 2), 0, Res);
12: // YYMMDDHHMMSS
Result := TryEncodeDateTime(Year2, IntAt(2, 2), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), IntAt(10, 2), 0, Res);
10: // YYMMDDHHMM
Result := TryEncodeDateTime(Year2, IntAt(2, 2), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), 0, 0, Res);
8: // YYYYMMDD
Result := TryEncodeDate(IntAt(0, 4), IntAt(4, 2), IntAt(6, 2), Res);
6: // YYMMDD
Result := TryEncodeDate(Year2, IntAt(2, 2), IntAt(4, 2), Res);
4: // YYMM
Result := TryEncodeDate(Year2, IntAt(2, 2), 1, Res);
2: // YY
Result := TryEncodeDate(Year2, 1, 1, Res);
else
Assert(False, 'Invalid FIELD_TYPE_TIMESTAMP FieldDesc.Length (' + IntToStr(FieldDesc.Length) + ')');
end;
FIELD_TYPE_DATE: // YYYY-MM-DD
Result := TryEncodeDate(IntAt(0, 4), IntAt(5, 2), IntAt(8, 2), Res);
FIELD_TYPE_TIME: // HH:MM:SS
begin
i := 0;
while Byte(Def[i + 1]) <> Byte(':') do begin
if i >= 4 then
DatabaseErrorFmt('Wrong time format. FieldDesc %s, value %s', [FieldDesc.Name, Def]);
Inc(i);
end;
Res := (IntAt(i + 1, 2) * 60 + IntAt(i + 4, 2)) / SecsPerDay; // MM:SS
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?