Skip to content

Commit

Permalink
Added single column anonymization feature
Browse files Browse the repository at this point in the history
  • Loading branch information
segovoni committed Oct 23, 2022
1 parent 97eb5a5 commit 1922030
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Packages/d103/sqlcmdcli.dproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_AutoIncVersion>true</VerInfo_AutoIncVersion>
<VerInfo_Keys>CompanyName=;FileDescription=Command-line utility for ad hoc, interactive execution of commands on SQL Server;FileVersion=1.0.0.67;InternalName=sqlcmdcli;LegalCopyright=;LegalTrademarks=;OriginalFilename=sqlcmdcli.exe;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0;Comments=https://github.com/segovoni/sqlcmdcli</VerInfo_Keys>
<VerInfo_Build>67</VerInfo_Build>
<VerInfo_Keys>CompanyName=;FileDescription=Command-line utility for ad hoc, interactive execution of commands on SQL Server;FileVersion=1.0.0.77;InternalName=sqlcmdcli;LegalCopyright=;LegalTrademarks=;OriginalFilename=sqlcmdcli.exe;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0;Comments=https://github.com/segovoni/sqlcmdcli</VerInfo_Keys>
<VerInfo_Build>77</VerInfo_Build>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
Expand Down
Binary file modified Packages/d103/sqlcmdcli.dres
Binary file not shown.
25 changes: 21 additions & 4 deletions Sources/sqlcmdcli.AnonymizeDB.pas
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ TAnonymizeDB = class(TObject)
class procedure DisableTriggers(const AConnection: TADOConnection;
const ATriggers: TDictionary<string, string>);
public
class procedure Run(const AServerName, ADatabaseName, AUserName, APassword: string;
const AVerbose: Boolean);
class procedure Run(const AServerName, ADatabaseName, AUserName, APassword,
ASchemaName, ATableName, AColumnName: string; const AVerbose: Boolean);
end;

implementation
Expand Down Expand Up @@ -174,7 +174,7 @@ class procedure TAnonymizeDB.EnableTriggers(const AConnection: TADOConnection;
end;

class procedure TAnonymizeDB.Run(const AServerName, ADatabaseName, AUserName,
APassword: string; const AVerbose: Boolean);
APassword, ASchemaName, ATableName, AColumnName: string; const AVerbose: Boolean);
var
LConnection: TADOConnection;
LDBSchema: TDBSchema;
Expand Down Expand Up @@ -224,7 +224,24 @@ class procedure TAnonymizeDB.Run(const AServerName, ADatabaseName, AUserName,
if (AVerbose) then
TConsole.Log(Format('Extract schema for %s ...', [ADatabaseName]), Success, False);

LDBSchemaExtractor.ExtractSchema(stText);
if (Trim(ASchemaName) = '') and
(Trim(ATableName) = '') and
(Trim(AColumnName) = '') then
begin
LDBSchemaExtractor.ExtractSchema(stText);
end
else if (Trim(ASchemaName) <> '') and
(Trim(ATableName) <> '') and
(Trim(AColumnName) <> '') then
begin
LDBSchemaExtractor.ExtractSchema(ASchemaName, ATableName, AColumnName);
end
else begin
if (AVerbose) then
TConsole.Log('Invalid parametes', Error, True);
raise Exception.Create('Invalid parametes');
end;

LDBSchema := LDBSchemaExtractor.DBSchema;
//LDBSchemaIndex := LDBSchemaExtractor.DBSchemaIndex;
finally
Expand Down
34 changes: 33 additions & 1 deletion Sources/sqlcmdcli.Boot.pas
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,40 @@ class procedure TBootCLI.Boot;
// Command: anonymizedb
LCommand := TOptionsRegistry.RegisterCommand('anonymizedb', 'anondb',
RS_CMD_ANONYMIZEDB_DESCRIPTION, RS_CMD_ANONYMIZEDB_INFO,
'anonymizedb -servername:<name> -databasename:<dbname> -username:<name> -password:<password>');
'anonymizedb -servername:<name> -databasename:<dbname> -username:<name> ' +
'-password:<password> -schemaname:<tableschema> -tablename:<tablename> ' +
'-columnname:<columnname>');
LCommand.Examples.Add('anonymizedb -servername:MARCONI -databasename:AdventureWorks -username:sgovoni -password:royalbreeze489');
LCommand.Examples.Add('anonymizedb -s:MARCONI -d:AdventureWorks -u:sgovoni -p:royalbreeze489');
LCommand.Examples.Add('anondb -s:MARCONI -d:AdventureWorks -u:sgovoni -p:royalbreeze489');

// Option: "schemaname"
LOption := LCommand.RegisterOption<string>('schemaname', 'schema',
RS_CMD_ANONYMIZEDB_SCHEMANAMEINFO,
procedure(const AValue: string)
begin
TAnonymizeDBOptions.SchemaName := AValue
end);
LOption.Required := False;

// Option: "tablename"
LOption := LCommand.RegisterOption<string>('tablename', 'table',
RS_CMD_ANONYMIZEDB_TABLENAMEINFO,
procedure(const AValue: string)
begin
TAnonymizeDBOptions.TableName := AValue
end);
LOption.Required := False;

// Option: "columnname"
LOption := LCommand.RegisterOption<string>('columnname', 'column',
RS_CMD_ANONYMIZEDB_COLUMNNAMEINFO,
procedure(const AValue: string)
begin
TAnonymizeDBOptions.ColumnName := AValue
end);
LOption.Required := False;

TCommandHandler.RegisterCommand('anonymizedb',
procedure()
begin
Expand All @@ -170,6 +199,9 @@ class procedure TBootCLI.Boot;
TGlobalOptions.DatabaseName,
TGlobalOptions.UserName,
TGlobalOptions.Password,
TAnonymizeDBOptions.SchemaName,
TAnonymizeDBOptions.TableName,
TAnonymizeDBOptions.ColumnName,
TGlobalOptions.Verbose);
end);

Expand Down
7 changes: 7 additions & 0 deletions Sources/sqlcmdcli.CommandOptions.pas
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ TAlterColumnOptions = class
class var DataType: string;
end;

TAnonymizeDBOptions = class
public
class var SchemaName: string;
class var TableName: string;
class var ColumnName: string;
end;

TGlobalOptions = class
public
class var ServerName: string;
Expand Down
3 changes: 3 additions & 0 deletions Sources/sqlcmdcli.ResourceStrings.pas
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ interface
'removing personally identifiable information from data sets, so that the ' +
'people whom the data describe remain anonymous (source ' +
'https://en.wikipedia.org/wiki/Data_anonymization)';
RS_CMD_ANONYMIZEDB_SCHEMANAMEINFO = 'The name of the table schema';
RS_CMD_ANONYMIZEDB_TABLENAMEINFO = 'The name of the table';
RS_CMD_ANONYMIZEDB_COLUMNNAMEINFO = 'The name of the column you want to modify';

RS_CMD_ANONYMIZEDB_DISABLE_FK_START = 'Disable foreign key constraints on %s ...';
RS_CMD_ANONYMIZEDB_DISABLE_FK_END = 'Foreign key constraints disabled successfully!';
Expand Down
109 changes: 108 additions & 1 deletion Sources/sqlcmdcli.SchemaExtractor.pas
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ TSQLDBSchemaExtractor = class(TObject)
function GetDBSchema: TDBSchema;
//function GetDBSchemaIndex: TDBSchemaIndex;
function GetSQLbySchemaType(ASchemaType: TSchemaType): string;
function GetSQLbySchema(const ASchemaName, ATableName, AColumnName: string): string;
protected
FConnection: TADOConnection;
FDBSchema: TDBSchema;
//FDBSchemaIndex: TDBSchemaIndex;
public
constructor Create(AConnection: TADOConnection);
destructor Destroy; override;
procedure ExtractSchema(ASchemaType: TSchemaType);
procedure ExtractSchema(ASchemaType: TSchemaType); overload;
procedure ExtractSchema(const ASchemaName, ATableName, AColumnName: string); overload;
property DBSchema: TDBSchema read GetDBSchema;
//property DBSchemaIndex: TDBSchemaIndex read GetDBSchemaIndex;
end;
Expand Down Expand Up @@ -78,6 +80,75 @@ destructor TSQLDBSchemaExtractor.Destroy;
inherited;
end;

procedure TSQLDBSchemaExtractor.ExtractSchema(const ASchemaName, ATableName,
AColumnName: string);
var
LQry: TADOQuery;
LCurrentTable: string;
LList: TObjectList<TSQLDBTableInfo>;
begin
// Database schema extractor logic

LQry := TADOQuery.Create(nil);
LList := TObjectList<TSQLDBTableInfo>.Create();
try
LQry.Connection := FConnection;
LQry.SQL.Text := GetSQLbySchema(ASchemaName, ATableName, AColumnName);
LQry.Open;

//
if not (LQry.Eof) then
LCurrentTable :=
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString) +
'.' +
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString);

while (not LQry.Eof) do
begin
if CompareText(LCurrentTable,
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString) + '.' +
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString)) = 0 then
begin
LList.Add(TSQLDBTableInfo.Create(
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('COLUMN_NAME').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('DATA_TYPE').AsString),
LQry.FieldByName('MAX_LENGHT').AsInteger,
LQry.FieldByName('COLUMN_IDENTITY').AsBoolean
)
)
end
else begin
FDBSchema.Add(LCurrentTable, LList);
LList := TObjectList<TSQLDBTableInfo>.Create();
LList.Add(TSQLDBTableInfo.Create(
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('COLUMN_NAME').AsString),
TSQLObjectNameFormatter.Format(LQry.FieldByName('DATA_TYPE').AsString),
LQry.FieldByName('MAX_LENGHT').AsInteger,
LQry.FieldByName('COLUMN_IDENTITY').AsBoolean
)
);
LCurrentTable :=
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString) +
'.' +
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString);
end;

LQry.Next;
end;

FDBSchema.Add(TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_SCHEMA').AsString) +
'.' +
TSQLObjectNameFormatter.Format(LQry.FieldByName('TABLE_NAME').AsString), LList);

finally
FreeAndNil(LQry);
end;
end;

procedure TSQLDBSchemaExtractor.ExtractSchema(ASchemaType: TSchemaType);
var
LQry: TADOQuery;
Expand Down Expand Up @@ -169,6 +240,42 @@ function TSQLDBSchemaExtractor.GetDBSchema: TDictionary<string, TOBjectList<TSQL
Result := FDBSchema;
end;

function TSQLDBSchemaExtractor.GetSQLbySchema(const ASchemaName, ATableName,
AColumnName: string): string;
begin
Result :=
'SELECT ' +
'TABLE_SCHEMA = SCHEMA_NAME(T.schema_id) ' +
',TABLE_NAME = T.name ' +
',ORDINAL_POSITION = C.column_id ' +
',COLUMN_NAME = C.name ' +
',MAX_LENGHT = C.max_length ' +
',DATA_TYPE = TYPE_NAME(C.system_type_id) ' +
',COLUMN_IDENTITY = C.is_identity ' +
//',ROWS = P.rows ' +
'FROM ' +
'sys.tables AS T ' +
'JOIN ' +
'sys.columns AS C ON T.object_id=C.object_id ' +
//'JOIN ' +
// 'sys.partitions AS P on P.object_id=T.object_id ' +
'WHERE ' +
'(T.type = ''U'') ' +
//'AND (T.is_memory_optimized = 0) ' +
'AND (T.is_ms_shipped = 0) ' +
'AND (T.temporal_type = 0) ' +
'AND (T.is_replicated = 0) ' +
'AND (C.is_computed = 0) ' +
'AND (SCHEMA_NAME(T.schema_id) = ''' + ASchemaName + ''') ' +
'AND (T.name = ''' + ATableName + ''') ' +
'AND (C.name = ''' + AColumnName + ''') ' +
'ORDER BY ' +
'TABLE_SCHEMA ' +
',TABLE_NAME ' +
',COLUMN_NAME ' +
',ORDINAL_POSITION';
end;

function TSQLDBSchemaExtractor.GetSQLbySchemaType(ASchemaType: TSchemaType): string;
begin
if (ASchemaType = stFull) then
Expand Down

0 comments on commit 1922030

Please sign in to comment.