git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.SDAC@3 6f543ec7-021b-7e4c-98c9-62eafc7fb9a8
487 lines
13 KiB
ObjectPascal
487 lines
13 KiB
ObjectPascal
//////////////////////////////////////////////////
|
|
// SQL Server Data Access Components
|
|
// Copyright © 1998-2007 Core Lab. All right reserved.
|
|
//////////////////////////////////////////////////
|
|
|
|
{$IFNDEF CLR}
|
|
|
|
{$I Sdac.inc}
|
|
|
|
unit MSDump;
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, DB, CRAccess, DBAccess, MSAccess, DADump, DAScript;
|
|
|
|
type
|
|
TMSDump = class;
|
|
|
|
//TMSDumpObject = (doData);
|
|
//TMSDumpObjects = set of TMSDumpObject;
|
|
|
|
TMSDumpOptions = class(TDADumpOptions)
|
|
protected
|
|
FIdentityInsert: boolean;
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
public
|
|
constructor Create(Owner: TMSDump);
|
|
published
|
|
property IdentityInsert: boolean read FIdentityInsert write FIdentityInsert default False;
|
|
end;
|
|
|
|
TMSDump = class(TDADump)
|
|
protected
|
|
//FObjects: TMSDumpObjects;
|
|
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
|
|
function GetTableInfoClass: TTableInfoClass; override;
|
|
|
|
function GetConnection: TMSConnection;
|
|
procedure SetConnection(Value: TMSConnection);
|
|
|
|
function GetTableNames: string; override;
|
|
procedure SetTableNames(Value: string); override;
|
|
|
|
function CreateOptions: TDADumpOptions; override;
|
|
function CreateScript: TDAScript; override;
|
|
|
|
function GetOptions: TMSDumpOptions;
|
|
procedure SetOptions(Value: TMSDumpOptions);
|
|
|
|
procedure InternalBackup(Query: string); override;
|
|
public
|
|
constructor Create(Owner: TComponent); override;
|
|
published
|
|
property Connection: TMSConnection read GetConnection write SetConnection;
|
|
|
|
//property Objects: TMSDumpObjects read FObjects write FObjects default [doData];
|
|
property Options: TMSDumpOptions read GetOptions write SetOptions;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF CLR}
|
|
System.Text, System.Runtime.InteropServices,
|
|
{$ELSE}
|
|
CLRClasses,
|
|
{$ENDIF}
|
|
{$IFDEF VER6P}
|
|
Variants,
|
|
{$ENDIF}
|
|
MemUtils, MemData, DAConsts, DALoader, OLEDBAccess, MSScript;
|
|
|
|
{ TMSDumpOptions }
|
|
|
|
constructor TMSDumpOptions.Create(Owner: TMSDump);
|
|
begin
|
|
inherited Create(Owner);
|
|
|
|
FIdentityInsert := False;
|
|
end;
|
|
|
|
procedure TMSDumpOptions.AssignTo(Dest: TPersistent);
|
|
begin
|
|
inherited;
|
|
|
|
if Dest is TMSDumpOptions then begin
|
|
TMSDumpOptions(Dest).IdentityInsert := IdentityInsert;
|
|
end;
|
|
end;
|
|
|
|
{ TMSDump }
|
|
|
|
constructor TMSDump.Create(Owner: TComponent);
|
|
begin
|
|
inherited Create(Owner);
|
|
|
|
//FObjects := [doData];
|
|
|
|
FLeftQuote := OLEDBAccess.LeftQuote;
|
|
FRightQuote := OLEDBAccess.RightQuote;
|
|
end;
|
|
|
|
procedure TMSDump.AssignTo(Dest: TPersistent);
|
|
begin
|
|
inherited;
|
|
|
|
if Dest is TMSDump then begin
|
|
//TMSDump(Dest).Objects := Objects;
|
|
end;
|
|
end;
|
|
|
|
function TMSDump.GetTableInfoClass: TTableInfoClass;
|
|
begin
|
|
Result := TOLEDBTableInfo;
|
|
end;
|
|
|
|
function TMSDump.GetConnection: TMSConnection;
|
|
begin
|
|
Result := TMSConnection(inherited Connection);
|
|
end;
|
|
|
|
procedure TMSDump.SetConnection(Value: TMSConnection);
|
|
begin
|
|
inherited Connection := Value;
|
|
end;
|
|
|
|
function TMSDump.GetTableNames: string;
|
|
begin
|
|
Result := TableNamesFromList(FTables);
|
|
end;
|
|
|
|
procedure TMSDump.SetTableNames(Value: string);
|
|
begin
|
|
TableNamesToList(Value, FTables);
|
|
end;
|
|
|
|
function TMSDump.CreateOptions: TDADumpOptions;
|
|
begin
|
|
Result := TMSDumpOptions.Create(nil);
|
|
end;
|
|
|
|
function TMSDump.CreateScript: TDAScript;
|
|
begin
|
|
Result := TMSScript.Create(nil);
|
|
end;
|
|
|
|
function TMSDump.GetOptions: TMSDumpOptions;
|
|
begin
|
|
Result := TMSDumpOptions(inherited Options);
|
|
end;
|
|
|
|
procedure TMSDump.SetOptions(Value: TMSDumpOptions);
|
|
begin
|
|
inherited Options := Value;
|
|
end;
|
|
|
|
{$IFNDEF CLR}
|
|
type
|
|
_StringBuilder = class (StringBuilder);
|
|
{$ENDIF}
|
|
|
|
procedure TMSDump.InternalBackup(Query: string);
|
|
var
|
|
MSQuery: TMSQuery;
|
|
TableCount: integer;
|
|
|
|
procedure VarToMSSQL(Field: TField; FieldDesc: TOLEDBFieldDesc; sb: StringBuilder);
|
|
var
|
|
dt: TDateTime;
|
|
Blob: TBlob;
|
|
Piece: PPieceHeader;
|
|
Value: Variant;
|
|
Data: TBytes;
|
|
{$IFNDEF VER6P}
|
|
pValueData: PVarData;
|
|
{$ENDIF}
|
|
{$IFDEF CLR}
|
|
Bytes: TBytes;
|
|
{$ELSE}
|
|
sbOffset: integer;
|
|
{$ENDIF}
|
|
begin
|
|
SetLength(Data, 0); // To avoid Hint from compiler
|
|
case FieldDesc.DataType of
|
|
dtBoolean:
|
|
sb.Append(BoolToStr(Field.AsBoolean));
|
|
dtUnknown, dtString, dtMemo, dtWideMemo, dtExtString, dtWideString, dtExtWideString, dtGuid{$IFDEF VER5P}, dtVariant{$ENDIF}:
|
|
sb.Append(QuotedStr(Field.AsString));
|
|
dtInt8, dtInt16, dtInt32, dtInt64,
|
|
dtUInt16, dtUInt32: begin
|
|
{$IFNDEF VER6P}
|
|
Value := Field.AsVariant;
|
|
pValueData := @TVarData(Value);
|
|
if pValueData.VType = varDecimal then
|
|
sb.Append(IntToStr(PInt64(@pValueData.VInteger)^))
|
|
else
|
|
{$ENDIF}
|
|
sb.Append(Field.AsString);
|
|
end;
|
|
dtFloat, dtCurrency:
|
|
sb.Append(ChangeDecimalSeparator(Field.AsString));
|
|
dtDate, dtTime, dtDateTime: begin
|
|
dt := Field.AsDateTime;
|
|
if dt = 0 then
|
|
sb.Append(QuotedStr('1900-01-01 00:00:00'))
|
|
else
|
|
sb.Append(QuotedStr(FormatDateTime('YYYY-MM-DD HH:NN:SS', dt)));
|
|
end;
|
|
dtBlob: begin
|
|
sb.Append('0x');
|
|
Blob := MSQuery.GetBlob(Field.FieldName);
|
|
Piece := Blob.FirstPiece;
|
|
|
|
{$IFDEF CLR}
|
|
while IntPtr(Piece) <> nil do begin
|
|
SetLength(Data, Piece.Used);
|
|
Marshal.Copy(IntPtr(Integer(Piece) + sizeof(TPieceHeader)), Data, 0, Piece.Used);
|
|
SetLength(Bytes, Length(Data) * 2);
|
|
BinToHex(Data, 0, Bytes, 0, Length(Data));
|
|
sb.Append(Encoding.Default.GetString(Bytes));
|
|
Piece := Piece.Next;
|
|
end;
|
|
{$ELSE}
|
|
sbOffset := sb.Length + 1;
|
|
sb.Length := sb.Length + Integer(Blob.Size) * 2;
|
|
while Piece <> nil do begin
|
|
BinToHex(IntPtr(Integer(Piece) + sizeof(TPieceHeader)),
|
|
IntPtr(Integer(@_StringBuilder(sb).FString[sbOffset])), Piece.Used);
|
|
sbOffset := sbOffset + Integer(Piece.Used);
|
|
Piece := Piece.Next;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
dtBytes, dtVarBytes, dtExtVarBytes: begin
|
|
sb.Append('0x');
|
|
Value := Field.Value;
|
|
Data := Value;
|
|
{$IFDEF CLR}
|
|
SetLength(Bytes, Length(Data) * 2);
|
|
BinToHex(Data, 0, Bytes, 0, Length(Data));
|
|
sb.Append(Encoding.Default.GetString(Bytes));
|
|
{$ELSE}
|
|
sbOffset := sb.Length + 1;
|
|
sb.Length := sb.Length + Length(Data) * 2;
|
|
BinToHex(@Data[0],
|
|
IntPtr(Integer(@_StringBuilder(sb).FString[sbOffset])), Length(Data));
|
|
{$ENDIF}
|
|
end;
|
|
else
|
|
Assert(False, 'Unknown datatype (' + IntToStr(FieldDesc.DataType) + ')');
|
|
end;
|
|
end;
|
|
|
|
procedure BackupTablesAndData;
|
|
|
|
function FieldIsIdentity(Field: TField): boolean;
|
|
var
|
|
FieldDesc: TOLEDBFieldDesc;
|
|
begin
|
|
FieldDesc := MSQuery.GetFieldDesc(Field) as TOLEDBFieldDesc;
|
|
Result := FieldDesc.IsAutoIncrement;
|
|
end;
|
|
|
|
procedure BackupTable(TableName: string; TableNum: integer);
|
|
var
|
|
KeyAndDataFields: TKeyAndDataFields;
|
|
|
|
procedure GetCurrentRow(sb: StringBuilder);
|
|
var
|
|
sbOldLen: integer;
|
|
|
|
procedure ProcessField(Field: TField);
|
|
var
|
|
Value: Variant;
|
|
FieldDesc: TOLEDBFieldDesc;
|
|
begin
|
|
if sbOldLen <> sb.Length then
|
|
sb.Append(', ');
|
|
|
|
Value := Field.AsVariant;
|
|
if VarIsEmpty(Value) or VarIsNull(Value) or Field.IsNull then
|
|
sb.Append('NULL')
|
|
else
|
|
begin
|
|
FieldDesc := MSQuery.GetFieldDesc(Field) as TOLEDBFieldDesc;
|
|
VarToMSSQL(Field, FieldDesc, sb);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
i: integer;
|
|
begin
|
|
sbOldLen := sb.Length;
|
|
|
|
if Length(KeyAndDataFields.DataFieldDescs) = 0 then begin
|
|
for i := 0 to MSQuery.FieldCount - 1 do
|
|
if not (FieldIsIdentity(MSQuery.Fields[i]) and not Options.IdentityInsert) then
|
|
ProcessField(MSQuery.Fields[i]);
|
|
end
|
|
else
|
|
begin
|
|
if (TDBAccessUtils.GetIdentityField(MSQuery) <> nil) and Options.IdentityInsert then
|
|
ProcessField(TDBAccessUtils.GetIdentityField(MSQuery));
|
|
for i := 0 to Length(KeyAndDataFields.DataFieldDescs) - 1 do
|
|
ProcessField(MSQuery.GetField(KeyAndDataFields.DataFieldDescs[i]));
|
|
end;
|
|
end;
|
|
|
|
var
|
|
RecordCount: integer;
|
|
InsHeader: string;
|
|
FieldList: string;
|
|
i: integer;
|
|
SQLSelect1: string;
|
|
sb: StringBuilder;
|
|
|
|
begin
|
|
FieldList := '';
|
|
if Query = '' then
|
|
SQLSelect1 := 'SELECT * FROM ' + TableName
|
|
else
|
|
SQLSelect1 := Query;
|
|
|
|
MSQuery.SQL.Text := SQLSelect1;
|
|
MSQuery.AddWhere('0=1');
|
|
try
|
|
MSQuery.Open;
|
|
|
|
if (TableName = '')
|
|
and (TDBAccessUtils.GetTablesInfo(MSQuery).Count > 0) then
|
|
TableName := TDBAccessUtils.GetTablesInfo(MSQuery)[0].TableName;
|
|
|
|
if (TDBAccessUtils.GetIdentityField(MSQuery) <> nil) and Options.IdentityInsert then
|
|
FieldList := QuoteName(TDBAccessUtils.GetIdentityField(MSQuery).FieldName);
|
|
|
|
TDBAccessUtils.GetKeyAndDataFields(MSQuery, KeyAndDataFields, False);
|
|
for i := 0 to Length(KeyAndDataFields.DataFieldDescs) - 1 do
|
|
if not (TOLEDBFieldDesc(KeyAndDataFields.DataFieldDescs[i]).IsAutoIncrement and not Options.IdentityInsert) then
|
|
if FieldList = '' then
|
|
FieldList := QuoteName(KeyAndDataFields.DataFieldDescs[i].Name)
|
|
else
|
|
FieldList := FieldList + ', ' + QuoteName(KeyAndDataFields.DataFieldDescs[i].Name);
|
|
finally
|
|
MSQuery.Close;
|
|
end;
|
|
|
|
if True {(doData in Objects)} then begin
|
|
if Options.GenerateHeader then
|
|
AddLineToSQL(SBHTableData, [TableName]);
|
|
|
|
if Options.AddDrop {and not (doTables in Objects)} then
|
|
Add('TRUNCATE TABLE ' + TableName + ';');
|
|
|
|
if Options.IdentityInsert then
|
|
Add(Format('SET IDENTITY_INSERT %s ON;', [TableName]));
|
|
|
|
MSQuery.SQL.Text := 'SELECT COUNT(*) FROM ' + TableName;
|
|
MSQuery.Execute;
|
|
RecordCount := MSQuery.Fields[0].AsInteger;
|
|
|
|
if Assigned(FOnBackupProgress) then
|
|
FOnBackupProgress(Self, TableName, TableNum, TableCount, 0);
|
|
|
|
if RecordCount > 0 then begin
|
|
if FieldList = '' then
|
|
InsHeader := TableName
|
|
else
|
|
InsHeader := TableName + '(' + FieldList + ')';
|
|
|
|
InsHeader := 'INSERT INTO ' + InsHeader + ' VALUES';
|
|
|
|
MSQuery.SQL.Text := SQLSelect1;
|
|
MSQuery.Open;
|
|
if FieldList <> '' then
|
|
TDBAccessUtils.GetKeyAndDataFields(MSQuery, KeyAndDataFields, False);
|
|
|
|
sb := StringBuilder.Create;
|
|
try
|
|
while not MSQuery.Eof do begin
|
|
if Assigned(FOnBackupProgress) then
|
|
FOnBackupProgress(Self, TableName, TableNum, TableCount, Trunc(MSQuery.RecNo * 100 / RecordCount));
|
|
|
|
sb.Length := 0;
|
|
sb.Append(InsHeader);
|
|
sb.Append(' (');
|
|
GetCurrentRow(sb);
|
|
sb.Append(');');
|
|
Add(sb.ToString);
|
|
MSQuery.Next;
|
|
end;
|
|
finally
|
|
sb.Free;
|
|
end;
|
|
end;
|
|
if Options.IdentityInsert then
|
|
Add(Format('SET IDENTITY_INSERT %s OFF;', [TableName]));
|
|
end;
|
|
end;
|
|
|
|
var
|
|
i: integer;
|
|
TablesList: TStringList;
|
|
TableName: string;
|
|
|
|
begin
|
|
if Query = '' then begin
|
|
TablesList := nil;
|
|
try
|
|
TablesList := TStringList.Create;
|
|
|
|
if FTables.Count = 0 then
|
|
GetTablesList(Connection, TablesList)
|
|
else
|
|
TablesList.Assign(FTables);
|
|
|
|
for i := 0 to TablesList.Count - 1 do begin
|
|
TableName := QuoteName(TablesList[i]);
|
|
|
|
if Assigned(FOnBackupProgress) then
|
|
FOnBackupProgress(Self, TableName, i, TablesList.Count, 0);
|
|
|
|
TableCount := TablesList.Count;
|
|
BackupTable(TableName, i);
|
|
Add('');
|
|
end;
|
|
|
|
finally
|
|
TablesList.Free;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if FTables.Count = 1 then
|
|
TableName := QuoteName(FTables[0])
|
|
else
|
|
TableName := '';
|
|
|
|
if Assigned(FOnBackupProgress) then
|
|
FOnBackupProgress(Self, TableName, 0, 1, 0);
|
|
|
|
TableCount := 1;
|
|
BackupTable(TableName, 0);
|
|
Add('');
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
BeginConnection;
|
|
try
|
|
Query := Trim(Query);
|
|
if (Query <> '') and (FTables.Count > 1) then
|
|
raise Exception.Create(SWrongTblCount);
|
|
MSQuery := nil;
|
|
FSQL.BeginUpdate;
|
|
try
|
|
FSQL.Text := '';
|
|
if Options.GenerateHeader then
|
|
AddLineToSQL(Format(SBHCaption, ['Sdac', SDACVersion,
|
|
'MS SQL', Connection.ServerVersion, 'MS SQL', Connection.ClientVersion, DateTimeToStr(Now),
|
|
Connection.Server, Connection.Database]));
|
|
|
|
MSQuery := TMSQuery.Create(nil);
|
|
MSQuery.Connection := Connection;
|
|
MSQuery.ReadOnly := False;
|
|
MSQuery.FetchAll := True;
|
|
MSQuery.UniDirectional := True;
|
|
MSQuery.Options.SetFieldsReadOnly := True;
|
|
MSQuery.Options.QueryRecCount := False;
|
|
|
|
// if doData in Objects then
|
|
BackupTablesAndData;
|
|
|
|
finally
|
|
FSQL.EndUpdate;
|
|
MSQuery.Free;
|
|
end;
|
|
finally
|
|
EndConnection;
|
|
end;
|
|
end;
|
|
|
|
end.
|