mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-19 20:39:25 +02:00
* Patch from Luiz Americo:
- Allow more than one field to be used in Locate (fix bug #7843) - Properly implement Edit, Insert, Cancel - Simplified TableExists - Make RecNo follows Delphi/sqldb (1 based count) git-svn-id: trunk@5711 -
This commit is contained in:
parent
b0bc5d92fd
commit
edc1015a49
@ -69,11 +69,11 @@ type
|
||||
{$else}
|
||||
FCurrentItem: PDataRecord;
|
||||
{$endif}
|
||||
FInternalActiveBuffer: PDataRecord;
|
||||
FBufferSize: Integer;
|
||||
FExpectedAppends: Integer;
|
||||
FExpectedDeletes: Integer;
|
||||
FExpectedUpdates: Integer;
|
||||
//FPersistentHandle: Boolean;
|
||||
FSaveOnClose: Boolean;
|
||||
FSaveOnRefetch: Boolean;
|
||||
FAutoIncrementKey: Boolean;
|
||||
@ -81,6 +81,7 @@ type
|
||||
FIndexFieldNames: String;
|
||||
FIndexFieldList: TList;
|
||||
FSqlList:TStrings;
|
||||
procedure CopyCacheToItem(AItem: PDataRecord);
|
||||
function GetIndexFields(Value: Integer): TField;
|
||||
procedure UpdateIndexFields;
|
||||
function FindRecordItem(StartItem: PDataRecord; const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions; DoResync:Boolean):PDataRecord;
|
||||
@ -135,7 +136,9 @@ type
|
||||
function GetRecordSize: Word; override;
|
||||
procedure InternalAddRecord(Buffer: Pointer; DoAppend: Boolean); override;
|
||||
procedure InternalClose; override;
|
||||
procedure InternalCancel; override;
|
||||
procedure InternalDelete; override;
|
||||
procedure InternalEdit; override;
|
||||
procedure InternalFirst; override;
|
||||
procedure InternalGotoBookmark(ABookmark: Pointer); override;
|
||||
procedure InternalInitRecord(Buffer: PChar); override;
|
||||
@ -173,8 +176,8 @@ type
|
||||
function QuickQuery(const ASql:String;const AStrList: TStrings;FillObjects:Boolean):String;virtual;abstract;overload;
|
||||
procedure RefetchData;
|
||||
function SqliteReturnString: String; virtual;abstract;
|
||||
function TableExists: Boolean;overload;
|
||||
function TableExists(const ATableName:String):Boolean;virtual;abstract;overload;
|
||||
function TableExists: Boolean;
|
||||
function TableExists(const ATableName:String):Boolean;
|
||||
function UpdatesPending: Boolean;
|
||||
{$ifdef DEBUGACTIVEBUFFER}
|
||||
procedure SetCurrentItem(Value:PDataRecord);
|
||||
@ -192,7 +195,6 @@ type
|
||||
property ExpectedDeletes: Integer read FExpectedDeletes write SetExpectedDeletes;
|
||||
property IndexFields[Value: Integer]: TField read GetIndexFields;
|
||||
property RowsAffected: Integer read GetRowsAffected;
|
||||
//property PersistentHandle: boolean read FPersistentHandle write FPersistentHandle;
|
||||
property SqliteReturnId: Integer read FSqliteReturnId;
|
||||
property SqliteHandle: Pointer read FSqliteHandle;
|
||||
property SqliteVersion: String read GetSqliteVersion;
|
||||
@ -239,11 +241,13 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
strutils, variants;
|
||||
strutils, variants, dbconst;
|
||||
|
||||
const
|
||||
SQLITE_OK = 0;//sqlite2.x.x and sqlite3.x.x defines this equal
|
||||
|
||||
//sqlite2.x.x and sqlite3.x.x define these constants equally
|
||||
SQLITE_OK = 0;
|
||||
SQLITE_ROW = 100;
|
||||
|
||||
function Num2SqlStr(APChar: PChar): String;
|
||||
begin
|
||||
if APChar = nil then
|
||||
@ -364,7 +368,6 @@ begin
|
||||
FEndItem^.Next:=nil;
|
||||
|
||||
FBeginItem^.BookMarkFlag:=bfBOF;
|
||||
FCacheItem^.BookMarkFlag:=bfEOF;
|
||||
FEndItem^.BookMarkFlag:=bfEOF;
|
||||
|
||||
FMasterLink:=TMasterDataLink.Create(Self);
|
||||
@ -382,19 +385,19 @@ begin
|
||||
end;
|
||||
|
||||
function TCustomSqliteDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
|
||||
var
|
||||
ActiveItem:PDataRecord;
|
||||
begin
|
||||
if Mode = bmWrite then
|
||||
begin
|
||||
ActiveItem:=PPDataRecord(ActiveBuffer)^;
|
||||
if (ActiveItem <> FCacheItem) and (FUpdatedItems.IndexOf(ActiveItem) = -1) and (FAddedItems.IndexOf(ActiveItem) = -1) then
|
||||
FUpdatedItems.Add(ActiveItem);
|
||||
StrDispose(ActiveItem^.Row[Field.FieldNo - 1]);
|
||||
ActiveItem^.Row[Field.FieldNo - 1]:=nil;
|
||||
if not (State in [dsEdit, dsInsert]) then
|
||||
begin
|
||||
DatabaseErrorFmt(SNotInEditState,[Name],Self);
|
||||
Exit;
|
||||
end;
|
||||
StrDispose(FCacheItem^.Row[Field.FieldNo - 1]);
|
||||
FCacheItem^.Row[Field.FieldNo - 1]:=nil;
|
||||
end;
|
||||
Result:= TDSStream.Create(PPDataRecord(ActiveBuffer)^,Field.FieldNo - 1);
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TCustomSqliteDataset.Destroy;
|
||||
begin
|
||||
@ -414,6 +417,19 @@ begin
|
||||
Dispose(FEndItem);
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.CopyCacheToItem(AItem: PDataRecord);
|
||||
var
|
||||
i:Integer;
|
||||
begin
|
||||
for i := 0 to FRowCount - 1 do
|
||||
begin
|
||||
StrDispose(AItem^.Row[i]);
|
||||
AItem^.Row[i]:=FCacheItem^.Row[i];
|
||||
FCacheItem^.Row[i]:=nil;
|
||||
end;
|
||||
AItem^.BookmarkFlag:=FCacheItem^.BookmarkFlag;
|
||||
end;
|
||||
|
||||
function TCustomSqliteDataset.GetIndexFields(Value: Integer): TField;
|
||||
begin
|
||||
if (Value < 0) or (Value > FIndexFieldList.Count - 1) then
|
||||
@ -560,27 +576,30 @@ var
|
||||
TempItem,TempActive:PDataRecord;
|
||||
begin
|
||||
Result:= -1;
|
||||
if FRecordCount = 0 then
|
||||
if (FRecordCount = 0) or (State = dsInsert) then
|
||||
Exit;
|
||||
TempItem:=FBeginItem;
|
||||
TempActive:=PPDataRecord(ActiveBuffer)^;
|
||||
if TempActive = FCacheItem then // Record not posted yet
|
||||
Result:=FRecordCount
|
||||
else
|
||||
while TempActive <> TempItem do
|
||||
if TempActive = FCacheItem then // Record is being edited
|
||||
begin
|
||||
TempActive:=FInternalActiveBuffer;
|
||||
end;
|
||||
//RecNo is 1 based
|
||||
inc(Result);
|
||||
while TempActive <> TempItem do
|
||||
begin
|
||||
if TempItem^.Next <> nil then
|
||||
begin
|
||||
if TempItem^.Next <> nil then
|
||||
begin
|
||||
inc(Result);
|
||||
TempItem:=TempItem^.Next;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result:=-1;
|
||||
DatabaseError('Sqliteds.GetRecNo - ActiveItem Not Found',Self);
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
inc(Result);
|
||||
TempItem:=TempItem^.Next;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result:=-1;
|
||||
DatabaseError('GetRecNo - ActiveItem Not Found',Self);
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomSqliteDataset.GetRecordSize: Word;
|
||||
@ -591,7 +610,6 @@ end;
|
||||
procedure TCustomSqliteDataset.InternalAddRecord(Buffer: Pointer; DoAppend: Boolean);
|
||||
var
|
||||
NewItem: PDataRecord;
|
||||
Counter:Integer;
|
||||
begin
|
||||
{$ifdef DEBUG}
|
||||
if PPDataRecord(Buffer)^ <> FCacheItem then
|
||||
@ -599,12 +617,20 @@ begin
|
||||
{$endif}
|
||||
New(NewItem);
|
||||
GetMem(NewItem^.Row,FRowBufferSize);
|
||||
for Counter := 0 to FRowCount - 1 do
|
||||
NewItem^.Row[Counter]:=StrNew(FCacheItem^.Row[Counter]);
|
||||
FEndItem^.Previous^.Next:=NewItem;
|
||||
NewItem^.Previous:=FEndItem^.Previous;
|
||||
NewItem^.Next:=FEndItem;
|
||||
FEndItem^.Previous:=NewItem;
|
||||
//necessary to nullify the Row before copy the cache
|
||||
FillChar(NewItem^.Row^,FRowBufferSize,#0);
|
||||
CopyCacheToItem(NewItem);
|
||||
|
||||
//insert in the linked list
|
||||
FCurrentItem^.Previous^.Next:=NewItem;
|
||||
NewItem^.Next:=FCurrentItem;
|
||||
NewItem^.Previous:=FCurrentItem^.Previous;
|
||||
FCurrentItem^.Previous:=NewItem;
|
||||
|
||||
//update the cursor in case of a insert
|
||||
if FCurrentItem <> FEndItem then
|
||||
FCurrentItem:=NewItem;
|
||||
|
||||
Inc(FRecordCount);
|
||||
if FAutoIncFieldNo <> - 1 then
|
||||
Inc(FNextAutoInc);
|
||||
@ -620,13 +646,6 @@ begin
|
||||
DestroyFields;
|
||||
if FDataAllocated then
|
||||
DisposeLinkedList;
|
||||
{
|
||||
if (FSqliteHandle <> nil) and not FPersistentHandle then
|
||||
begin
|
||||
InternalCloseHandle;
|
||||
FSqliteHandle := nil;
|
||||
end;
|
||||
}
|
||||
FAddedItems.Clear;
|
||||
FUpdatedItems.Clear;
|
||||
FDeletedItems.Clear;
|
||||
@ -634,6 +653,19 @@ begin
|
||||
FRecordCount:=0;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalCancel;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
PPDataRecord(ActiveBuffer)^:=FInternalActiveBuffer;
|
||||
//free the cache
|
||||
for i:= 0 to FRowCount - 1 do
|
||||
begin
|
||||
StrDispose(FCacheItem^.Row[i]);
|
||||
FCacheItem^.Row[i]:=nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalDelete;
|
||||
var
|
||||
TempItem:PDataRecord;
|
||||
@ -669,6 +701,19 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalEdit;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
FInternalActiveBuffer:=PPDataRecord(ActiveBuffer)^;
|
||||
//copy active item to cache
|
||||
for i:= 0 to FRowCount - 1 do
|
||||
FCacheItem^.Row[i]:=StrNew(FInternalActiveBuffer^.Row[i]);
|
||||
FCacheItem^.BookmarkFlag:=FInternalActiveBuffer^.BookmarkFlag;
|
||||
//now active buffer is the cache item
|
||||
PPDataRecord(ActiveBuffer)^:=FCacheItem;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalFirst;
|
||||
begin
|
||||
FCurrentItem := FBeginItem;
|
||||
@ -681,14 +726,8 @@ end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalInitRecord(Buffer: PChar);
|
||||
var
|
||||
Counter:Integer;
|
||||
TempStr:String;
|
||||
begin
|
||||
for Counter:= 0 to FRowCount - 1 do
|
||||
begin
|
||||
StrDispose(FCacheItem^.Row[Counter]);
|
||||
FCacheItem^.Row[Counter]:=nil;
|
||||
end;
|
||||
if FAutoIncFieldNo <> - 1 then
|
||||
begin
|
||||
Str(FNextAutoInc,TempStr);
|
||||
@ -696,6 +735,7 @@ begin
|
||||
StrPCopy(FCacheItem^.Row[FAutoIncFieldNo],TempStr);
|
||||
end;
|
||||
PPDataRecord(Buffer)^:=FCacheItem;
|
||||
FCacheItem^.BookmarkFlag:=bfInserted;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalLast;
|
||||
@ -732,7 +772,6 @@ begin
|
||||
FSelectSqlStr:=FSelectSqlStr+FieldDefs[i].Name+',';
|
||||
FSelectSqlStr:=FSelectSqlStr+FieldDefs[FieldDefs.Count - 1].Name+
|
||||
' FROM '+FTableName;
|
||||
//writeln(FSelectSqlStr);
|
||||
|
||||
if DefaultFields then
|
||||
CreateFields;
|
||||
@ -759,8 +798,16 @@ end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalPost;
|
||||
begin
|
||||
if (State<>dsEdit) then
|
||||
InternalAddRecord(ActiveBuffer,True);
|
||||
if State <> dsEdit then
|
||||
InternalAddRecord(ActiveBuffer,True)
|
||||
else
|
||||
begin
|
||||
CopyCacheToItem(FInternalActiveBuffer);
|
||||
PPDataRecord(ActiveBuffer)^:=FInternalActiveBuffer;
|
||||
if (FUpdatedItems.IndexOf(FInternalActiveBuffer) = -1) and
|
||||
(FAddedItems.IndexOf(FInternalActiveBuffer) = -1) then
|
||||
FUpdatedItems.Add(FInternalActiveBuffer);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.InternalSetToRecord(Buffer: PChar);
|
||||
@ -775,23 +822,59 @@ end;
|
||||
|
||||
function TCustomSqliteDataset.FindRecordItem(StartItem: PDataRecord; const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions; DoResync:Boolean):PDataRecord;
|
||||
var
|
||||
ValueArray: array of string;
|
||||
IndexArray: array of integer;
|
||||
AFieldList: TList;
|
||||
i,AFieldCount:Integer;
|
||||
MatchRecord: Boolean;
|
||||
AValue:String;
|
||||
AField:TField;
|
||||
AFieldIndex:Integer;
|
||||
TempItem:PDataRecord;
|
||||
begin
|
||||
Result:=nil;
|
||||
// Now, it allows to search only one field and ignores options
|
||||
AField:=Fields.FieldByName(KeyFields); //FieldByName raises an exception if field not found
|
||||
AFieldIndex:=AField.FieldNo - 1;
|
||||
//get float types in appropriate format
|
||||
if not (AField.DataType in [ftFloat,ftDateTime,ftTime,ftDate]) then
|
||||
AValue:=keyvalues
|
||||
else
|
||||
begin
|
||||
Str(VarToDateTime(keyvalues),AValue);
|
||||
AValue:=Trim(AValue);
|
||||
end;
|
||||
// Currently ignore options
|
||||
AFieldList:=TList.Create;
|
||||
try
|
||||
GetFieldList(AFieldList,KeyFields);
|
||||
AFieldCount:=AFieldList.Count;
|
||||
if AFieldCount > 1 then
|
||||
begin
|
||||
if VarIsArray(KeyValues) then
|
||||
begin
|
||||
if Succ(VarArrayHighBound(KeyValues,1)) <> AFieldCount then
|
||||
DatabaseError('Number of fields does not correspond to number of values',Self);
|
||||
end
|
||||
else
|
||||
DatabaseError('Wrong number of values specified: expected an array of variants got a variant',Self);
|
||||
end;
|
||||
|
||||
//set the array of values and indexes
|
||||
|
||||
SetLength(ValueArray,AFieldCount);
|
||||
SetLength(IndexArray,AFieldCount);
|
||||
for i:= 0 to AFieldCount - 1 do
|
||||
with TField(AFieldList[i]) do
|
||||
begin
|
||||
//get float types in appropriate format
|
||||
if not (DataType in [ftFloat,ftDateTime,ftTime,ftDate]) then
|
||||
begin
|
||||
if VarIsArray(KeyValues) then
|
||||
ValueArray[i]:=keyvalues[i]
|
||||
else
|
||||
ValueArray[i]:=keyvalues;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if VarIsArray(KeyValues) then
|
||||
Str(VarToDateTime(keyvalues[i]),AValue)
|
||||
else
|
||||
Str(VarToDateTime(keyvalues),AValue);
|
||||
ValueArray[i]:=Trim(AValue);
|
||||
end;
|
||||
IndexArray[i]:=FieldNo - 1;
|
||||
end;
|
||||
finally
|
||||
AFieldList.Destroy;
|
||||
end;
|
||||
{$ifdef DEBUG}
|
||||
writeln('##TCustomSqliteDataset.FindRecordItem##');
|
||||
writeln(' KeyFields: ',keyfields);
|
||||
@ -802,19 +885,27 @@ begin
|
||||
TempItem:=StartItem;
|
||||
while TempItem <> FEndItem do
|
||||
begin
|
||||
if TempItem^.Row[AFieldIndex] <> nil then
|
||||
MatchRecord:=True;
|
||||
for i:= 0 to AFieldCount - 1 do
|
||||
begin
|
||||
if StrComp(TempItem^.Row[AFieldIndex],PChar(AValue)) = 0 then
|
||||
//todo: handle null values??
|
||||
if (TempItem^.Row[IndexArray[i]] = nil) or
|
||||
(StrComp(TempItem^.Row[IndexArray[i]],PChar(ValueArray[i])) <> 0) then
|
||||
begin
|
||||
Result:=TempItem;
|
||||
if DoResync then
|
||||
begin
|
||||
FCurrentItem:=TempItem;
|
||||
Resync([]);
|
||||
end;
|
||||
Break;
|
||||
MatchRecord:= False;
|
||||
Break;//for
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if MatchRecord then
|
||||
begin
|
||||
Result:=TempItem;
|
||||
if DoResync then
|
||||
begin
|
||||
FCurrentItem:=TempItem;
|
||||
Resync([]);
|
||||
end;
|
||||
Break;//while
|
||||
end;
|
||||
TempItem:=TempItem^.Next;
|
||||
end;
|
||||
end;
|
||||
@ -850,7 +941,7 @@ end;
|
||||
|
||||
procedure TCustomSqliteDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
|
||||
begin
|
||||
//The BookMarkData is the Buffer itself;
|
||||
//The BookMarkData is the Buffer itself: no need to set nothing;
|
||||
end;
|
||||
|
||||
procedure TCustomSqliteDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
|
||||
@ -878,50 +969,50 @@ procedure TCustomSqliteDataset.SetFieldData(Field: TField; Buffer: Pointer;
|
||||
NativeFormat: Boolean);
|
||||
var
|
||||
TempStr:String;
|
||||
ActiveItem:PDataRecord;
|
||||
begin
|
||||
ActiveItem:=PPDataRecord(ActiveBuffer)^;
|
||||
if (ActiveItem <> FCacheItem) and (FUpdatedItems.IndexOf(ActiveItem) = -1) and (FAddedItems.IndexOf(ActiveItem) = -1) then
|
||||
FUpdatedItems.Add(ActiveItem);
|
||||
|
||||
StrDispose(ActiveItem^.Row[Pred(Field.FieldNo)]);
|
||||
if not (State in [dsEdit, dsInsert]) then
|
||||
begin
|
||||
DatabaseErrorFmt(SNotInEditState,[Name],Self);
|
||||
Exit;
|
||||
end;
|
||||
StrDispose(FCacheItem^.Row[Pred(Field.FieldNo)]);
|
||||
if Buffer <> nil then
|
||||
begin
|
||||
case Field.Datatype of
|
||||
ftString:
|
||||
begin
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=StrNew(PChar(Buffer));
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=StrNew(PChar(Buffer));
|
||||
end;
|
||||
ftInteger:
|
||||
begin
|
||||
Str(LongInt(Buffer^),TempStr);
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(ActiveItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(FCacheItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
end;
|
||||
ftBoolean,ftWord:
|
||||
begin
|
||||
Str(Word(Buffer^),TempStr);
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(ActiveItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(FCacheItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
end;
|
||||
ftFloat,ftDateTime,ftDate,ftTime,ftCurrency:
|
||||
begin
|
||||
Str(Double(Buffer^),TempStr);
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr));
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr));
|
||||
//Skips the first space that str returns
|
||||
//todo: make a custom Str?
|
||||
Move((PChar(TempStr)+1)^,(ActiveItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr));
|
||||
Move((PChar(TempStr)+1)^,(FCacheItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr));
|
||||
end;
|
||||
ftLargeInt:
|
||||
begin
|
||||
Str(Int64(Buffer^),TempStr);
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(ActiveItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
|
||||
Move(PChar(TempStr)^,(FCacheItem^.Row[Pred(Field.FieldNo)])^,Length(TempStr)+1);
|
||||
end;
|
||||
end;// case
|
||||
end//if
|
||||
else
|
||||
ActiveItem^.Row[Pred(Field.FieldNo)]:=nil;
|
||||
FCacheItem^.Row[Pred(Field.FieldNo)]:=nil;
|
||||
if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
|
||||
DataEvent(deFieldChange, Ptrint(Field));
|
||||
end;
|
||||
@ -936,10 +1027,11 @@ var
|
||||
Counter:Integer;
|
||||
TempItem:PDataRecord;
|
||||
begin
|
||||
if (Value >= FRecordCount) or (Value < 0) then
|
||||
if (Value > FRecordCount) or (Value <= 0) then
|
||||
DatabaseError('Record Number Out Of Range',Self);
|
||||
CheckBrowseMode;
|
||||
TempItem:=FBeginItem;
|
||||
for Counter := 0 to Value do
|
||||
for Counter := 1 to Value do
|
||||
TempItem:=TempItem^.Next;
|
||||
FCurrentItem:=TempItem;
|
||||
Resync([]);
|
||||
@ -1280,6 +1372,16 @@ begin
|
||||
Result:=TableExists(FTableName);
|
||||
end;
|
||||
|
||||
function TCustomSqliteDataset.TableExists(const ATableName: String): Boolean;
|
||||
begin
|
||||
Result:=False;
|
||||
if not (ATableName = '') and FileExists(FFileName) then
|
||||
begin
|
||||
ExecSql('SELECT name FROM SQLITE_MASTER WHERE type = ''table'' AND name LIKE '''+ ATableName+ ''';');
|
||||
Result:=FSqliteReturnId = SQLITE_ROW;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomSqliteDataset.UpdatesPending: Boolean;
|
||||
begin
|
||||
//Sometimes FBeginItem is inserted in FUpdatedItems
|
||||
|
@ -41,13 +41,11 @@ type
|
||||
procedure InternalCloseHandle;override;
|
||||
procedure BuildLinkedList; override;
|
||||
protected
|
||||
procedure InternalCancel;override;
|
||||
procedure InternalInitFieldDefs; override;
|
||||
function GetRowsAffected:Integer; override;
|
||||
public
|
||||
procedure ExecuteDirect(const ASql: String);override;
|
||||
function SqliteReturnString: String; override;
|
||||
function TableExists(const ATableName:String): Boolean;override;
|
||||
function QuickQuery(const ASql:String;const AStrList: TStrings;FillObjects:Boolean):String;override;
|
||||
end;
|
||||
|
||||
@ -256,81 +254,6 @@ begin
|
||||
FBeginItem^.Row[Counter]:=nil;
|
||||
end;
|
||||
|
||||
procedure TSqlite3Dataset.InternalCancel;
|
||||
{
|
||||
var
|
||||
vm:Pointer;
|
||||
i:Integer;
|
||||
ActiveItem:PDataRecord;
|
||||
ASql:String;
|
||||
}
|
||||
begin
|
||||
{
|
||||
//WriteLn('InternalCancel called');
|
||||
if FPrimaryKeyNo <> - 1 then //requires a primarykey
|
||||
begin
|
||||
ActiveItem:=PPDataRecord(ActiveBuffer)^;
|
||||
if ActiveItem = FBeginItem then //Dataset is empty
|
||||
Exit;
|
||||
for i:= 0 to FRowCount -1 do
|
||||
StrDispose(ActiveItem^.Row[i]);
|
||||
|
||||
if FAddedItems.IndexOf(ActiveItem) <> -1 then //the record is not in the database
|
||||
begin
|
||||
for i:= 0 to FRowCount - 1 do
|
||||
begin
|
||||
ActiveItem^.Row[i]:=nil;
|
||||
//DataEvent(deFieldChange, Ptrint(Fields[i]));
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
ASql:=FSelectSqlStr+' Where '+Fields[FPrimaryKeyNo].FieldName+
|
||||
' = '+StrPas(ActiveItem^.Row[FPrimaryKeyNo]);
|
||||
//writeln(Asql);
|
||||
sqlite3_prepare(FSqliteHandle,PChar(ASql),-1,@vm,nil);
|
||||
if sqlite3_step(vm) = SQLITE_ROW then
|
||||
begin
|
||||
for i:= 0 to FRowCount - 1 do
|
||||
begin
|
||||
ActiveItem^.Row[i]:=StrNew(sqlite3_column_text(vm,i));
|
||||
//DataEvent(deFieldChange, Ptrint(Fields[i]));
|
||||
end;
|
||||
end;
|
||||
sqlite3_finalize(vm);
|
||||
end;
|
||||
}
|
||||
end;
|
||||
|
||||
function TSqlite3Dataset.TableExists(const ATableName:String): Boolean;
|
||||
var
|
||||
vm:Pointer;
|
||||
begin
|
||||
{$ifdef DEBUG}
|
||||
writeln('##TSqlite3Dataset.TableExists##');
|
||||
{$endif}
|
||||
Result:=False;
|
||||
if not (ATableName = '') and FileExists(FFileName) then
|
||||
begin
|
||||
if FSqliteHandle = nil then
|
||||
GetSqliteHandle;
|
||||
FSqliteReturnId:=sqlite3_prepare(FSqliteHandle,
|
||||
Pchar('SELECT name FROM SQLITE_MASTER WHERE type = ''table'' AND name LIKE '''+ ATableName+ ''';'),
|
||||
-1,@vm,nil);
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' sqlite3_prepare - SqliteReturnString:',SqliteReturnString);
|
||||
{$endif}
|
||||
FSqliteReturnId:=sqlite3_step(vm);
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' sqlite3_step - SqliteReturnString:',SqliteReturnString);
|
||||
{$endif}
|
||||
Result:=FSqliteReturnId = SQLITE_ROW;
|
||||
sqlite3_finalize(vm);
|
||||
end;
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' Table '+ATableName+' exists: ',Result);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
function TSqlite3Dataset.SqliteReturnString: String;
|
||||
begin
|
||||
case FSqliteReturnId of
|
||||
|
@ -47,7 +47,6 @@ type
|
||||
public
|
||||
procedure ExecuteDirect(const ASql: String);override;
|
||||
function SqliteReturnString: String; override;
|
||||
function TableExists(const ATableName:String): Boolean;override;
|
||||
function QuickQuery(const ASql:String;const AStrList: TStrings;FillObjects:Boolean):String;override;
|
||||
property SqliteEncoding: String read GetSqliteEncoding;
|
||||
end;
|
||||
@ -74,93 +73,6 @@ begin
|
||||
Result:=1;
|
||||
end;
|
||||
|
||||
{
|
||||
function GetFieldDefs(TheDataset: Pointer; Columns: Integer; ColumnValues: PPChar; ColumnNames: PPChar): integer; cdecl;
|
||||
var
|
||||
FieldSize:Word;
|
||||
i:Integer;
|
||||
AType:TFieldType;
|
||||
ColumnStr:String;
|
||||
begin
|
||||
//Prepare the array of pchar2sql functions
|
||||
SetLength(TCustomSqliteDataset(TheDataset).FGetSqlStr,Columns);
|
||||
// Sqlite is typeless (allows any type in any field)
|
||||
// regardless of what is in Create Table, but returns
|
||||
// exactly what is in Create Table statement
|
||||
// here is a trick to get the datatype.
|
||||
// If the field contains another type, may have problems
|
||||
for i:= 0 to Columns - 1 do
|
||||
begin
|
||||
ColumnStr:= UpperCase(StrPas(ColumnNames[i + Columns]));
|
||||
if (ColumnStr = 'INTEGER') or (ColumnStr = 'INT') then
|
||||
begin
|
||||
if TCustomSqliteDataset(TheDataset).AutoIncrementKey and
|
||||
(UpperCase(StrPas(ColumnNames[i])) = UpperCase(TCustomSqliteDataset(TheDataset).PrimaryKey)) then
|
||||
begin
|
||||
AType:= ftAutoInc;
|
||||
DummyAutoIncFieldNo:=i;
|
||||
end
|
||||
else
|
||||
AType:= ftInteger;
|
||||
FieldSize:=SizeOf(LongInt);
|
||||
end else if Pos('VARCHAR',ColumnStr) = 1 then
|
||||
begin
|
||||
AType:= ftString;
|
||||
FieldSize:=0;
|
||||
end else if Pos('BOOL',ColumnStr) = 1 then
|
||||
begin
|
||||
AType:= ftBoolean;
|
||||
FieldSize:=SizeOf(WordBool);
|
||||
end else if Pos('AUTOINC',ColumnStr) = 1 then
|
||||
begin
|
||||
AType:= ftAutoInc;
|
||||
FieldSize:=SizeOf(LongInt);
|
||||
if DummyAutoIncFieldNo = -1 then
|
||||
DummyAutoIncFieldNo:= i;
|
||||
end else if (Pos('FLOAT',ColumnStr)=1) or (Pos('NUMERIC',ColumnStr)=1) then
|
||||
begin
|
||||
AType:= ftFloat;
|
||||
FieldSize:=SizeOf(Double);
|
||||
end else if (ColumnStr = 'DATETIME') then
|
||||
begin
|
||||
AType:= ftDateTime;
|
||||
FieldSize:=SizeOf(TDateTime);
|
||||
end else if (ColumnStr = 'DATE') then
|
||||
begin
|
||||
AType:= ftDate;
|
||||
FieldSize:=SizeOf(TDateTime);
|
||||
end else if (ColumnStr = 'TIME') then
|
||||
begin
|
||||
AType:= ftTime;
|
||||
FieldSize:=SizeOf(TDateTime);
|
||||
end else if (ColumnStr = 'LARGEINT') then
|
||||
begin
|
||||
AType:= ftLargeInt;
|
||||
FieldSize:=SizeOf(LargeInt);
|
||||
end else if (ColumnStr = 'TEXT') then
|
||||
begin
|
||||
AType:= ftMemo;
|
||||
FieldSize:=0;
|
||||
end else if (ColumnStr = 'CURRENCY') then
|
||||
begin
|
||||
AType:= ftCurrency;
|
||||
FieldSize:=SizeOf(Double);
|
||||
end else if (ColumnStr = 'WORD') then
|
||||
begin
|
||||
AType:= ftWord;
|
||||
FieldSize:=SizeOf(Word);
|
||||
end else
|
||||
begin
|
||||
AType:=ftString;
|
||||
FieldSize:=0;
|
||||
end;
|
||||
TDataset(TheDataset).FieldDefs.Add(StrPas(ColumnNames[i]), AType, FieldSize, False);
|
||||
//Set
|
||||
end;
|
||||
Result:=-1;
|
||||
end;
|
||||
}
|
||||
|
||||
{ TSqliteDataset }
|
||||
|
||||
function TSqliteDataset.SqliteExec(AHandle: Pointer; ASql: PChar): Integer;
|
||||
@ -349,38 +261,6 @@ begin
|
||||
FBeginItem^.Row[Counter]:=nil;
|
||||
end;
|
||||
|
||||
function TSqliteDataset.TableExists(const ATableName:String): Boolean;
|
||||
var
|
||||
vm:Pointer;
|
||||
ColumnNames,ColumnValues:PPChar;
|
||||
AInt:Integer;
|
||||
begin
|
||||
{$ifdef DEBUG}
|
||||
WriteLn('##TSqliteDataset.TableExists##');
|
||||
{$endif}
|
||||
Result:=False;
|
||||
if not (ATableName = '') and FileExists(FFileName) then
|
||||
begin
|
||||
if FSqliteHandle = nil then
|
||||
GetSqliteHandle;
|
||||
FSqliteReturnId:=sqlite_compile(FSqliteHandle,
|
||||
Pchar('SELECT name FROM SQLITE_MASTER WHERE type = ''table'' AND name LIKE '''+ ATableName+ ''';'),
|
||||
nil,@vm,nil);
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' sqlite_compile - SqliteReturnString:',SqliteReturnString);
|
||||
{$endif}
|
||||
FSqliteReturnId:=sqlite_step(vm,@AInt,@ColumnValues,@ColumnNames);
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' sqlite_step - SqliteReturnString:',SqliteReturnString);
|
||||
{$endif}
|
||||
Result:=FSqliteReturnId = SQLITE_ROW;
|
||||
sqlite_finalize(vm, nil);
|
||||
end;
|
||||
{$ifdef DEBUG}
|
||||
WriteLn(' Table '+ATableName+' exists:',Result);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
function TSqliteDataset.SqliteReturnString: String;
|
||||
begin
|
||||
case FSqliteReturnId of
|
||||
|
Loading…
Reference in New Issue
Block a user