TBufDataset.First issue. lazarus / 16-Databases ---------------------------------------------------------------------- dmitryb · 2023-01-24 18:18 Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64 Next code in Lazarus 2.2.4  shows empty string. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button4Click(Sender: TObject);var  s: String;begin  BufDataset1 := TBufDataset.Create(Self);   BufDataset1.FieldDefs.Add('Str5Field', ftString, 5, -1, False, False, 0, CP_UTF8);  BufDataset1.CreateDataset;   BufDataset1.Append;  BufDataset1.FieldByName('Str5Field').AsString := 'ABCDEFG';  BufDataset1.Post;  BufDataset1.First;   s := VarToStr(BufDataset1.FieldByName('Str5Field').AsVariant);   ShowMessage(s);end;  Is this a feature or a bug? ---------------------------------------------------------------------- egsuh · 2023-01-25 03:26 Why not simply      s := BufDataset1.FieldByName('Str5Field').AsString; ? ---------------------------------------------------------------------- Zvoni · 2023-01-25 08:21 Quote from: egsuh on January 25, 2023, 04:26:46 amWhy not simply      s := BufDataset1.FieldByName('Str5Field').AsString; ? Same issue. I can confirm Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1;Uses bufdataset,db; Var  s:String;  bd:TBufDataset; begin  bd:=TBufDataset.Create(Nil);  bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,0,CP_UTF8);  bd.CreateDataset;  Writeln('RecCount=',bd.RecordCount);  bd.Append;  bd.FieldByName('Str5Field').AsString:='ABCDEFG';  bd.Post;  Writeln('RecCount=',bd.RecordCount);  Writeln('BOF=',bd.BOF,' - EOF=',bd.EOF);  s:=bd.Fieldbyname('Str5Field').AsString;  Writeln('recNo=',bd.RecNo,' - s=',s);  bd.First;  Writeln('BOF=',bd.BOF,' - EOF=',bd.EOF);  s:=bd.Fieldbyname('Str5Field').AsString;  Writeln('recNo=',bd.RecNo,' - s=',s);  bd.Last;  Writeln('BOF=',bd.BOF,' - EOF=',bd.EOF);  s:=bd.Fieldbyname('Str5Field').AsString;  Writeln('recNo=',bd.RecNo,' - s=',s);  bd.First;  Writeln('BOF=',bd.BOF,' - EOF=',bd.EOF);  s:=bd.Fieldbyname('Str5Field').AsString;  Writeln('recNo=',bd.RecNo,' - s=',s);end. Result QuoteRecCount=0 RecCount=1 BOF=FALSE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s= BOF=FALSE - EOF=TRUE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s= ---------------------------------------------------------------------- TRon · 2023-01-25 08:46 In addition to Zvoni's findings: - it leaks memory - it creates an access violation when not using a exception block to free the instantiated class. I get very strange output characters instead of receiving empty strings (unlike Zvoni) ---------------------------------------------------------------------- Zvoni · 2023-01-25 09:14 Quote from: TRon on January 25, 2023, 09:46:15 amIn addition to Zvoni's findings: - it leaks memory - it creates an access violation when not using a exception block to free the instantiated class. Yes, it's the reason why i left out bd.free in above code (and i don't care about memory-leaks when just testing around and it's basically the end of the program anyway) Something that baffles me: RecCount is 1, shouldn't BOF and EOF both be true, irrespective if i move Next, Prior, First or Last?? ---------------------------------------------------------------------- rvk · 2023-01-25 09:22 The problem might be that you are trying to stuff a string of 7 characters "ABCDEFG" in a field defined with Size = 5 !! That really messes things up. Just define the stringfield as a field of 20 characters and the code should work fine. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,0,CP_UTF8);  bd.FieldDefs.Add('Str5Field', ftString, 20); (I'm also not sure about the other parameters you used in the field-def. But the simple version I used above works.) ---------------------------------------------------------------------- Zvoni · 2023-01-25 09:24 Quote from: rvk on January 25, 2023, 10:22:21 amThe problem might be that you are trying to stuff a string of 7 characters "ABCDEFG" in a field defined with Size = 5 !! That really messes things up. Just define the stringfield as a field of 20 characters and the code should work fine. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,0,CP_UTF8);  bd.FieldDefs.Add('Str5Field', ftString, 20); Was my first thought, too, but doesn't make a difference if you shorten the String to "ABCDE" - same issue. Just try it. EDIT: What i noticed: The issue appears when BOF=True, irrespective of the Value of EOF It returns the correct Value for BOF=False ---------------------------------------------------------------------- rvk · 2023-01-25 09:26 Quote from: Zvoni on January 25, 2023, 10:24:08 amQuote from: rvk on January 25, 2023, 10:22:21 amThe problem might be that you are trying to stuff a string of 7 characters "ABCDEFG" in a field defined with Size = 5 !! That really messes things up. Just define the stringfield as a field of 20 characters and the code should work fine. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,0,CP_UTF8);  bd.FieldDefs.Add('Str5Field', ftString, 20); Was my first thought, too, but doesn't make a difference if you shorten the String to "ABCDE" - same issue. Just try it. And what happens if you use this?? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  bd.FieldDefs.Add('Str5Field', ftString, 20); The problem could also be in the precision of -1 or something else. Using the simple Add() version works for me. O, or FieldNo. Why is 0 used here? Shouldn't this be 1???? ---------------------------------------------------------------------- Zvoni · 2023-01-25 09:28 Quote from: rvk on January 25, 2023, 10:26:08 amQuote from: Zvoni on January 25, 2023, 10:24:08 amQuote from: rvk on January 25, 2023, 10:22:21 amThe problem might be that you are trying to stuff a string of 7 characters "ABCDEFG" in a field defined with Size = 5 !! That really messes things up. Just define the stringfield as a field of 20 characters and the code should work fine. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,0,CP_UTF8);  bd.FieldDefs.Add('Str5Field', ftString, 20); Was my first thought, too, but doesn't make a difference if you shorten the String to "ABCDE" - same issue. Just try it. And what happens if you use this?? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  bd.FieldDefs.Add('Str5Field', ftString, 20); The problem could also be in the precision of -1 or something else. Using the simple Add() version works for me. Yes, i wondered about that, too (since when do you need precision for Strings?!?!), but i think OP used this overloaded function because of the following params after precision (required, readonly, codepage) ---------------------------------------------------------------------- rvk · 2023-01-25 09:29 Quote from: Zvoni on January 25, 2023, 10:28:27 amYes, i wondered about that, too (since when do you need precision for Strings?!?!), but i think OP used this overloaded function because of the following params after precision (required, readonly, codepage) I think the fieldNo of 0 is the problem. Make it one (1) and it works. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field', ftString, 20);  bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,1,CP_UTF8); ---------------------------------------------------------------------- rvk · 2023-01-25 09:34 Quote from: rvk on January 25, 2023, 10:29:57 amQuote from: Zvoni on January 25, 2023, 10:28:27 amYes, i wondered about that, too (since when do you need precision for Strings?!?!), but i think OP used this overloaded function because of the following params after precision (required, readonly, codepage) I think the fieldNo of 0 is the problem. Make it one (1) and it works. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field', ftString, 20);  bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,1,CP_UTF8); Yep. From the source: Quote  // the fielddef will register itself here as an owned component.   // fieldno is 1 based ! So don't use field 0 but start on 1 !!!! Not sure if there is any documentation for this ---------------------------------------------------------------------- Zvoni · 2023-01-25 09:40 QuoteQuote from: rvk on January 25, 2023, 10:34:34 am Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // bd.FieldDefs.Add('Str5Field', ftString, 20);  bd.FieldDefs.Add('Str5Field',ftString,5,-1,False,False,1,CP_UTF8); Yep. From the source: Quote  // the fielddef will register itself here as an owned component.   // fieldno is 1 based ! So don't use field 0 but start on 1 !!!! Not sure if there is any documentation for this  Yep, that's it. Result QuoteRecCount=0 RecCount=1 BOF=FALSE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=FALSE - EOF=TRUE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG Still doesn't explain the BOF/EOF confusion ---------------------------------------------------------------------- TRon · 2023-01-25 09:45 Confirmed that rvk's solution works. I agree with Zvoni wrt documentation (I was unable to locate it, though the property is named fielNo as in number not index). Even a exception on providing a 'illegal' field number would have been helpful. I seem to remember there being something being off with eof/bof. From what I remember it was logical it acted this way (I seem unable to locate the conversation as I was not part of it, should be here on the forum) ---------------------------------------------------------------------- rvk · 2023-01-25 09:45 Quote from: Zvoni on January 25, 2023, 10:40:48 amResult QuoteRecCount=0 RecCount=1 BOF=FALSE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=FALSE - EOF=TRUE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG Still doesn't explain the BOF/EOF confusion What confusion? They are correct in this example. (or am I missing something?) BOF and EOF are not set until they are actually encountered. With a POST they are not set. Only with Last, First, Next and Prior (and only in the direction you where going). ---------------------------------------------------------------------- wp · 2023-01-25 09:45 Quote from: rvk on January 25, 2023, 10:34:34 amNot sure if there is any documentation for this  https://www.freepascal.org/docs-html/fcl/db/tfield.fieldno.html ("It is a 1-based index") ---------------------------------------------------------------------- TRon · 2023-01-25 09:48 Quote from: wp on January 25, 2023, 10:45:58 amQuote from: rvk on January 25, 2023, 10:34:34 amNot sure if there is any documentation for this  https://www.freepascal.org/docs-html/fcl/db/tfield.fieldno.html ("It is a 1-based index") Ok, I came in from another end: https://www.freepascal.org/docs- html/fcl/db/tfielddef.fieldno.html ---------------------------------------------------------------------- Zvoni · 2023-01-25 10:04 Quote from: rvk on January 25, 2023, 10:45:44 amQuote from: Zvoni on January 25, 2023, 10:40:48 amResult QuoteRecCount=0 RecCount=1 BOF=FALSE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG BOF=FALSE - EOF=TRUE recNo=1 - s=ABCDEFG BOF=TRUE - EOF=FALSE recNo=1 - s=ABCDEFG Still doesn't explain the BOF/EOF confusion What confusion? They are correct in this example. (or am I missing something?) BOF and EOF are not set until they are actually encountered. With a POST they are not set. Only with Last, First, Next and Prior (and only in the direction you where going). For a RecordCount = 1 i would expect BOF and EOF to be True. Or at least EOF to be True from the get-go, since OP used Append ---------------------------------------------------------------------- rvk · 2023-01-25 10:11 Quote from: Zvoni on January 25, 2023, 11:04:36 amFor a RecordCount = 1 i would expect BOF and EOF to be True. No. BOF and EOF are only set on movement of the cursor. Quote1. The cursor is on the last record, and the TDataset.Next method is called.https://www.freepascal.org/docs- html/fcl/db/tdataset.eof.html So, although you are on the last record after Append with one record, Next isn't called, so EOF is false. Although the documentation page of BOF isn't that clear, the same as for EOF goes for BOF. Only exception is when there is an empty dataset. Then both BOF and EOF are true. Also note: QuoteIn all other cases, EOF is False. Note: when the cursor is on the last-but-one record, and Next is called (moving the cursor to the last record), EOF will not yet be True.So, EOF will only trigger if you are trying to go past the last record. Not when you reach that last record. (That's why you do a while EOF loop with Next on the end, otherwise this would go wrong) ---------------------------------------------------------------------- wp · 2023-01-25 10:15 Quote from: TRon on January 25, 2023, 10:48:23 amOk, I came in from another end: https://www.freepascal.org/docs- html/fcl/db/tfielddef.fieldno.html I agree that it is "poorly documented". I just know this because I once was involved in a bug fix related to ZEOS components which changed their RecNo to begin at 0, and this caused some trouble (https://sourceforge.net/p/zeoslib/tickets/539/). ---------------------------------------------------------------------- Zvoni · 2023-01-25 10:32 Quote from: rvk on January 25, 2023, 11:11:07 amQuote from: Zvoni on January 25, 2023, 11:04:36 amFor a RecordCount = 1 i would expect BOF and EOF to be True. No. BOF and EOF are only set on movement of the cursor. Quote1. The cursor is on the last record, and the TDataset.Next method is called.https://www.freepascal.org/docs- html/fcl/db/tdataset.eof.html So, although you are on the last record after Append with one record, Next isn't called, so EOF is false. Although the documentation page of BOF isn't that clear, the same as for EOF goes for BOF. Only exception is when there is an empty dataset. Then both BOF and EOF are true. Also note: QuoteIn all other cases, EOF is False. Note: when the cursor is on the last-but-one record, and Next is called (moving the cursor to the last record), EOF will not yet be True.So, EOF will only trigger if you are trying to go past the last record. Not when you reach that last record. (That's why you do a while EOF loop with Next on the end, otherwise this would go wrong) Ah... OK. I've just read something on Microsofts website, and it is consistent BOF/EOF will only be set to True if you try to MOVE BEYOND the First/Last record ---------------------------------------------------------------------- TRon · 2023-01-25 10:53 Quote from: Zvoni on January 25, 2023, 11:32:31 amBOF/EOF will only be set to True if you try to MOVE BEYOND the First/Last record Ah, yes !!. That was the conclusion from the conversation I remembered as well. Thx for the refresh guys/galls ! ---------------------------------------------------------------------- Thaddy · 2023-01-25 13:08 An old example from 2016 written by me and already on this forum:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$apptype console}{$mode objfpc}uses  db,BufDataset;var  BufDb:TBufDataset;begin BufDb:=TBufDataset.Create(nil); try   BufDb.FieldDefs.Add('NAME',ftString,20);   BufDb.FieldDefs.Add('NUM',ftinteger);   BufDb.FieldDefs.Add('NUM2',ftInteger);   BufDb.CreateDataSet;   BufDb.Open;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Free';   BufDb.Post;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Pascal';   BufDb.Post;   BufDb.SaveToFile('BufDb.txt'); finally   BufDb.Close;   BufDb.Free; end; // now, open.. BufDb := TBufDataset.Create(nil); try   BufDb.LoadFromFile('BufDb.txt');   BufDb.Open;   BufDb.First;   Writeln(BufDb.FieldByName('NAME').Value); finally   BufDb.Close;   BufDb.Free; end; end. It seems to me that just the call to open is the culprit. https://forum.lazarus.freepascal.org/index.php/topic,33508.msg217317.h tml#msg217317 ---------------------------------------------------------------------- Zvoni · 2023-01-25 13:30 Quote from: Thaddy on January 25, 2023, 02:08:55 pmAn old example from 2016 written by me and already on this forum:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$apptype console}{$mode objfpc}uses  db,BufDataset;var  BufDb:TBufDataset;begin BufDb:=TBufDataset.Create(nil); try   BufDb.FieldDefs.Add('NAME',ftString,20);   BufDb.FieldDefs.Add('NUM',ftinteger);   BufDb.FieldDefs.Add('NUM2',ftInteger);   BufDb.CreateDataSet;   BufDb.Open;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Free';   BufDb.Post;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Pascal';   BufDb.Post;   BufDb.SaveToFile('BufDb.txt'); finally   BufDb.Close;   BufDb.Free; end; // now, open.. BufDb := TBufDataset.Create(nil); try   BufDb.LoadFromFile('BufDb.txt');   BufDb.Open;   BufDb.First;   Writeln(BufDb.FieldByName('NAME').Value); finally   BufDb.Close;   BufDb.Free; end; end. It seems to me that just the call to open is the culprit. https://forum.lazarus.freepascal.org/index.php/topic,33508.msg217317.h tml#msg217317 No, it was the FieldNo in the (overloaded) Add-Function. OP (and myself) missed that FieldNo is 1-based. OP used for that sample FieldNo=0 ---------------------------------------------------------------------- Thaddy · 2023-01-25 19:00 I wouldn't call it no!, because if you want to read the first entry, first will do nicely. Hence that old example. It is cleaner and much easier than the bull dung above. ---------------------------------------------------------------------- egsuh · 2023-01-26 02:09 In Zvony’s example, calling RecNo might have moved cursor beyond last record.