自己修改ZeosDBO使其支持加密的SQLite
昨天提交了一些相关的代码去Source Forge,得到的结果是,对方毫不理睬,并且已经删除了我提交的代码
我尊重他们的协议,不自行发布修改后的Zeos,因此,只能将修改方法公开,以便各位自行修改。
要改的地方不是太多,大家看着我的改法,自己改一下就好了,不是很麻烦
[b]一、修改ZPlainSqLiteDriver.pas[/b]
这个文件位于\src\plain目录下
在接口IZSQLitePlainDriver内,修改Open()方法的定义
原始的定义为:[color=#0000ff]function [/color]Open([color=#0000ff]const [/color]filename: PChar; mode: Integer; [color=#0000ff]var [/color]errmsg: PChar): Psqlite;
修改为:[color=#0000ff]function [/color]Open([color=#0000ff]const [/color]filename: PChar; mode: Integer;password: PChar; [color=#0000ff]var [/color]errmsg: PChar): Psqlite;
在类TZSQLite28PlainDriver内,修改Open()方法的定义
修改方法同上,定义是一样的
在类TZSQLite3PlainDriver 内,做同样的修改
继续往下,找到 TZSQLite3PlainDriver.Open()方法,作如下修改:
原始的代码为:
[code]function TZSQLite3PlainDriver.Open(const filename: PChar; mode: Integer; var errmsg: PChar): Psqlite;
var
Result0: Psqlite;
Version: string;
FileNameString: String;
begin
Result0:= nil;
Version := LibVersion;
FileNameString := filename;
{$IFNDEF VER130}
if (Version > '3.2.5') then
ZPlainSqLite3.sqlite_open(PAnsiChar(AnsiToUTF8(FileNameString)), Result0)
else
{$ENDIF}
ZPlainSqLite3.sqlite_open(filename, Result0);
Result := Result0;
end;[/code]
修改为:[code]function TZSQLite3PlainDriver.Open(const filename: PChar; mode: Integer; password: PChar; var errmsg: PChar): Psqlite;
var
Result0: Psqlite;
Version: string;
FileNameString: String;
begin
Result0:= nil;
Version := LibVersion;
FileNameString := filename;
{$IFNDEF VER130}
if (Version > '3.2.5') then
ZPlainSqLite3.sqlite_open(PAnsiChar(AnsiToUTF8(FileNameString)), Result0)
else
{$ENDIF}
ZPlainSqLite3.sqlite_open(filename, Result0);
Result := Result0;
if password <> EmptyStr then <-- 此处修改
ZPlainSqLite3.sqlite_key(Result0, password, Length(password));
end;[/code]
[b]二、修改ZDbcSqLite.pas[/b]
这个文件位于\src\dbc目录下
找到TZSQLiteConnection.Open()方法,作如下修改:
原始代码为:[code]procedure TZSQLiteConnection.Open;
var
ErrorCode: Integer;
ErrorMessage: PChar;
LogMessage: string;
SQL: string;
begin
if not Closed then Exit;
ErrorMessage := '';
LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
FHandle := FPlainDriver.Open(PChar(Database), 0, ErrorMessage);
if FHandle = nil then
begin
CheckSQLiteError(FPlainDriver, SQLITE_ERROR, ErrorMessage, lcConnect, LogMessage);
end;
DriverManager.LogMessage(lcConnect, FPlainDriver.GetProtocol, LogMessage);
{ Turn on encryption if requested }
if StrToBoolEx(Info.Values['encrypted']) then
begin
ErrorCode := FPlainDriver.Key(FHandle, PChar(Password), StrLen(PChar(Password)));
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcConnect, 'SQLite.Key');
end;
try
SQL := 'PRAGMA show_datatypes = ON';
ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL), nil, nil, ErrorMessage);
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);
{
SQL := 'PRAGMA empty_result_callbacks = ON';
ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),
nil, nil, ErrorMessage);
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);
}
StartTransactionSupport;
except
FPlainDriver.Close(FHandle);
FHandle := nil;
raise;
end;
inherited Open;
end;[/code]
修改为:[code]procedure TZSQLiteConnection.Open;
var
ErrorCode: Integer;
ErrorMessage: PChar;
LogMessage: string;
SQL: string;
begin
if not Closed then Exit;
ErrorMessage := '';
LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]);
FHandle := FPlainDriver.Open(PChar(Database), 0, PChar(Password), ErrorMessage); <-- 此处修改
if FHandle = nil then
begin
CheckSQLiteError(FPlainDriver, SQLITE_ERROR, ErrorMessage, lcConnect, LogMessage);
end;
DriverManager.LogMessage(lcConnect, FPlainDriver.GetProtocol, LogMessage);
{ Turn on encryption if requested }
if StrToBoolEx(Info.Values['encrypted']) then
begin
ErrorCode := FPlainDriver.Key(FHandle, PChar(Password), StrLen(PChar(Password)));
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcConnect, 'SQLite.Key');
end;
try
SQL := 'PRAGMA show_datatypes = ON';
ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL), nil, nil, ErrorMessage);
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);
{
SQL := 'PRAGMA empty_result_callbacks = ON';
ErrorCode := FPlainDriver.Execute(FHandle, PChar(SQL),
nil, nil, ErrorMessage);
CheckSQLiteError(FPlainDriver, ErrorCode, ErrorMessage, lcExecute, SQL);
}
StartTransactionSupport;
except
FPlainDriver.Close(FHandle);
FHandle := nil;
raise;
end;
inherited Open;
end;[/code[]
三、修改ZDbcSqliteUtils.pas
这个文件位于\src\dbc目录下
找到ConvertSQLiteTypeToSQLType()法,作如下修改:
原始代码为:[code]
function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer;
var Decimals: Integer): TZSQLType;
var
P1, P2: Integer;
Temp: string;
begin
TypeName := UpperCase(TypeName);
Result := stString;
Precision := 0;
Decimals := 0;
P1 := Pos('(', TypeName);
P2 := Pos(')', TypeName);
if (P1 > 0) and (P2 > 0) then
begin
Temp := Copy(TypeName, P1 + 1, P2 - P1 - 1);
TypeName := Copy(TypeName, 1, P1 - 1);
P1 := Pos(',', Temp);
if P1 > 0 then
begin
Precision := StrToIntDef(Copy(Temp, 1, P1 - 1), 0);
Decimals := StrToIntDef(Copy(Temp, P1 + 1, Length(Temp) - P1), 0);
end else
Precision := StrToIntDef(Temp, 0);
end;
if StartsWith(TypeName, 'BOOL') then
Result := stBoolean
else if TypeName = 'TINYINT' then
Result := stByte
else if TypeName = 'SMALLINT' then
Result := stShort
else if TypeName = 'MEDIUMINT' then
Result := stInteger
else if StartsWith(TypeName, 'INT') then
Result := stInteger
else if TypeName = 'BIGINT' then
Result := stLong
else if StartsWith(TypeName, 'REAL') then
Result := stDouble
else if StartsWith(TypeName, 'FLOAT') then
Result := stDouble
else if (TypeName = 'NUMERIC') or (TypeName = 'DECIMAL')
or (TypeName = 'NUMBER') then
begin
{ if Decimals = 0 then
Result := stInteger
else} Result := stDouble;
end
else if StartsWith(TypeName, 'DOUB') then
Result := stDouble
else if TypeName = 'MONEY' then
Result := stBigDecimal
else if StartsWith(TypeName, 'CHAR') then
Result := stString
else if TypeName = 'VARCHAR' then
Result := stString
else if TypeName = 'VARBINARY' then
Result := stBytes
else if TypeName = 'BINARY' then
Result := stBytes
else if TypeName = 'DATE' then
Result := stDate
else if TypeName = 'TIME' then
Result := stTime
else if TypeName = 'TIMESTAMP' then
Result := stTimestamp
else if TypeName = 'DATETIME' then
Result := stTimestamp
else if Pos('BLOB', TypeName) > 0 then
Result := stBinaryStream
else if Pos('CLOB', TypeName) > 0 then
Result := stAsciiStream
else if Pos('TEXT', TypeName) > 0 then
Result := stAsciiStream;
if (Result = stInteger) and (Precision <> 0) then
begin
if Precision <= 2 then
Result := stByte
else if Precision <= 4 then
Result := stShort
else if Precision <= 9 then
Result := stInteger
else Result := stLong;
end;
if (Result = stString) and (Precision = 0) then
Precision := 256;
end;[/code]
修改为:[code]function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer;
var Decimals: Integer): TZSQLType;
var
P1, P2: Integer;
Temp: string;
begin
TypeName := UpperCase(TypeName);
Result := stString;
Precision := 0;
Decimals := 0;
P1 := Pos('(', TypeName);
P2 := Pos(')', TypeName);
if (P1 > 0) and (P2 > 0) then
begin
Temp := Copy(TypeName, P1 + 1, P2 - P1 - 1);
TypeName := Copy(TypeName, 1, P1 - 1);
P1 := Pos(',', Temp);
if P1 > 0 then
begin
Precision := StrToIntDef(Copy(Temp, 1, P1 - 1), 0);
Decimals := StrToIntDef(Copy(Temp, P1 + 1, Length(Temp) - P1), 0);
end else
Precision := StrToIntDef(Temp, 0);
end;
if StartsWith(TypeName, 'BOOL') then
Result := stBoolean
else if TypeName = 'TINYINT' then
Result := stByte
else if TypeName = 'SMALLINT' then
Result := stShort
else if TypeName = 'MEDIUMINT' then
Result := stInteger
else if StartsWith(TypeName, 'INT') then
Result := stInteger
else if TypeName = 'BIGINT' then
Result := stLong
else if StartsWith(TypeName, 'REAL') then
Result := stDouble
else if StartsWith(TypeName, 'FLOAT') then
Result := stDouble
else if (TypeName = 'NUMERIC') or (TypeName = 'DECIMAL')
or (TypeName = 'NUMBER') then
begin
{ if Decimals = 0 then
Result := stInteger
else} Result := stDouble;
end
else if StartsWith(TypeName, 'DOUB') then
Result := stDouble
else if TypeName = 'MONEY' then
Result := stBigDecimal
else if StartsWith(TypeName, 'CHAR') then
Result := stString
else if TypeName = 'VARCHAR' then
Result := stString
else if TypeName = 'VARBINARY' then
Result := stBytes
else if TypeName = 'BINARY' then
Result := stBytes
else if TypeName = 'DATE' then
Result := stDate
else if TypeName = 'TIME' then
Result := stTime
else if TypeName = 'TIMESTAMP' then
Result := stTimestamp
else if TypeName = 'DATETIME' then
Result := stTimestamp
else if Pos('BLOB', TypeName) > 0 then
Result := stBinaryStream
else if Pos('CLOB', TypeName) > 0 then
Result := stAsciiStream
else if Pos('TEXT', TypeName) > 0 then
Result := stString; <-- 此处修改
if (Result = stInteger) and (Precision <> 0) then
begin
if Precision <= 2 then
Result := stByte
else if Precision <= 4 then
Result := stShort
else if Precision <= 9 then
Result := stInteger
else Result := stLong;
end;
if (Result = stString) and (Precision = 0) then
Precision := 4096; <-- 此处修改
end;[/code]
四、保存修改,编译,安装
经过修改的Zeos即可支持加密的SQLite数据库,示例代码如下:[code]ZConnection1.Password := 'sa';
ZConnection1.Connect;
ZTable1.TableName := 'Employees';
ZTable1.Open;[/code]