Jump to content

Lars Fosdal

Administrators
  • Content Count

    3323
  • Joined

  • Last visited

  • Days Won

    110

Everything posted by Lars Fosdal

  1. Lars Fosdal

    [Firedac] Truncation error on Firebird select query

    I assume the problem does not happen if you trim :PARAM manually? Could it be that StrsTrim2Len only deals with insert/update parameterization and not selects?
  2. The other day, I discovered that you can't use Exit() in a finally section. Needless to say, I had a second go at that code.
  3. Lars Fosdal

    My android app restarts on permission request

    function SelectDirectory calls ForceDirectories, and there is no raise in the TDirectoryListBox class. Anyways - ForceDirectories can cause an exception under the specified circumstances - so the real question is: What is the content of PIKAFolder when it is passed to ForceDirectories, and - if not blank - what happens if the folder already exists?
  4. Lars Fosdal

    My android app restarts on permission request

    Actually, http://docwiki.embarcadero.com/CodeExamples/Rio/en/DirListBoxUpdate_(C%2B%2B) says and a look at it in the source code verifies it.
  5. Lars Fosdal

    My android app restarts on permission request

    Is there a risk that ForceDirectories can fail with an exception? /offtopic: Comparisons with boolean values make me cringe.
  6. @David Schwartz - What about vanilla FireDAC? Doesn't the FD drivers fully hide the differences between Oracle and PostgreSQL?
  7. @Remy Lebeau Yeah, that can be a good idea. Or, you do like we do, and have various custom query builder classes that produce a final string - which you then pass on.
  8. I wonder when we will get nullable types. That will be awesome for DB related code.
  9. A rough draft from the top of my head. I've made the two query types look a little different from what they probably actually are to point out how the encapsulation hides the differences. Your actual wrapper will be different, and the number of methods that you need to wrap depends on the various TDataSet descendants and how you use them now. The wrapper exposes the properties and methods I need. type TxQuery<T: TDataSet> = class abstract private FiQuery: T; protected procedure SetSQL(aValue: string); ; virtual; abstract; function GetSQL: string; virtual; abstract; function GetDataSet: TDataSet; virtual; abstract; property iQuery: T read FiQuery write FiQuery; public procedure Execute; virtual; abstract; property SQL: string read GetSQL write SetSQL; property DataSet: TDataSet read GetDataSet; end TxQueryClass = class of TxQuery; TxOraQuery = class TxQuery<TOracleDataset> protected procedure SetSQL(aValue: string); override; function GetSQL: string; override; function GetDataSet: TDataSet; virtual; abstract; end; TxPgQuery = class TxQuery<TPgQuery> protected procedure SetSQL(aValue: string); override; function GetSQL: string; override; function GetDataSet: TDataSet; virtual; abstract; end; procedure TxOraQuery.SetSQL(aValue: string); begin iQuery.SQL.Text := aValue; end; function TxOraQuery.GetSQL: string; begin Result := iQuery.SQL.Text; end; function TxOraQuery.GetDataSet: TDataSet; begin Result := iQuery; end; procedure TxPgQuery.SetSQL(aValue: string); begin iQuery.SQL := aValue; end; function TxPgQuery.GetSQL: string; begin Result := iQuery.SQL; end; function TxPgQuery.GetDataSet: TDataSet; begin Result := iQuery.DataSet; end; type TForm1 = class(TForm) var QryClass: TxQueryClass; procedure FormCreate; procedure TestQuery(aQuery: TxQuery; aSQL: string); end; procedure TForm1.FormCreate; begin if Config = Pg then QryClass := TxPgQuery else QryClass := TxOraQuery; end; procedure TForm1.TestQuery; var Qry: TxQuery; SQL: string; begin Qry := QryClass.Create; Proc1(Qry, aSQL); end; procedure TForm1.Proc1(aQuery: TxQuery; aSQL: string); begin aQuery.DataSet.Close; aQuery.SQL := aSQL; aQuery.DataSet.Open; ... end;
  10. I'll get back to you on this, @David Schwartz Think base class, inheritance and encapsulation.
  11. Thanks guys, Good observations. The dates in question are set to whatever FireDAC returns from a SQL Server datetime field, which typically appears to be 0 for NULL. The set date range is always in the future, relatively speaking. If the date is less than today, it is an expired dairy product by definition. We don't sell those 😉 I'll change the requirement for blank dates to be <= 1.0 to be on the safe side.
  12. At least that confirms that I am not blind. EMBT has fumbled on the doc here. Too bad as I have I wanted to use a custom converter to take a Json stream that have a mixed type list and convert it to/from a single object in Delphi, but I didn't have the patience and aptitude to dig that deep. { "list": [ 5, "thing", {"object":"type"} ] } It is the Message structure from the Google+Exporter Json https://docs.google.com/document/d/1gOYJe61sI1GbO9qpFZJtwY3vdsZalsxtPgUnB2cvzAw/edit
  13. @Uwe RaabeThat is beautiful! But - where the heck is the documentation for this!?
  14. We chose to do wrapper classes that further abstract the actual database types away from our code. Hence, in our code, there is no difference between running a BDE wrapped ADO connection and a FireDAC connection. Those classes use old school encapsulation to hide such differences from our code with very little overhead.
  15. Thanks! Neither suggestion is "perfect", but that gives me something to work with. I wonder how expensive it would be to do suggestion 1 for every structure that I use? There are supposed to be ways to plug in validators and converters for TJson & family, but the documentation is non-existent, and I don't want to take time to reverse engineer it all.
  16. Lars Fosdal

    Best site/source for SQL Server questions?

    We do all data change via SPs of which some do not do explicit transaction handling. The current SP call handling will detect if the call was a deadlock victim and rerun it if necessary - but that basically escalates the risk of yet another deadlock. The bigger sites have nearly a hundred pickers - so the odds for concurrent access = inevitable. We need to identify where we do not need exclusive access and explicitly use NoLock where appropriate. We need to identify where transactions will be feasible / required. We need to identify a best practice for resource allocation. The challenge is that the rules are complex and the dataset is dynamic (pallets are emptied and replaced many, many times during a day). f.x. get the best pick position for n items of article x with date requirement y which has the best fit for our pick route and least incoming traffic. To further complicate it, different clients have different rules for date requirements due to longer transports or specific rules per article for shorter requirements due to high turnover. The list of these varying parameters go on and on. If two clients make the same request at the same time - one has to be the winner of what may be a scarce resource, while the other needs a viable plan b. The pick request may consume the remaining items on one pallet, and then grab the rest from the next pallet - if there is one. To further complicate it, the allocation may need to be split onto multiple deliveries to multiple clients within the pick order. What is blatantly clear is that we currently are not doing it the optimal way.
  17. Lars Fosdal

    Possible bug in debugger for Delphi 10.3.1

    Debugger improvements were on the most recent roadmaps, wasn't they?
  18. Does anyone recognize that seemingly hardcoded address? The call stack indicates that it happens in Rio 10.3.1 source - but searching the source does not yield anything. Can it be Eurekalog that tries to tell me something about referencing a deleted or inaccessible piece of memory? #BAD: EAccessViolation: Access violation at address 0040CEEC in module 'MyApp.exe'. Read of address DEADBEE7. DBServer\INDUSTRIELL\DBName # 3017235 20.03.2019 13:23:06 (Brukerinterface, CRITICAL) MyApp_ClientId @ [0040CEEC] System._UStrAsg __________ CallStack [0040CEEC] System._UStrAsg [01561AF4] System.Generics.Collections.pas.{GridSet}TGridSet.TFieldValue<System.string>.SetValue (Line 4745, "System.Generics.Collections.pas") [0156241F] System.Generics.Collections.pas.{GridSet}TGridSet.TFieldValue<System.string>.CopyRow (Line 4745, "System.Generics.Collections.pas") [01558452] GridSet.TGridSet.CopyRow (Line 1002, "GridSet.pas") [01B92885] frmPSDExpeditionDeliveries2.TDeliverySet.UpdateFromDeliverySet (Line 4108, "frmPSDExpeditionDeliveries2.pas") [01B8F919] frmPSDExpeditionDeliveries2.TDeliveryGrid.RefreshByRouteList (Line 3671, "frmPSDExpeditionDeliveries2.pas")
  19. Lars Fosdal

    Read of address DEADBEE7. - Source of this raise?

    Excellent analysis, Remy. As I often do, I did not ask the right question - which should have been: What sets dead memory references to $DEADxxxx? RTL? EurekaLog? OS?
  20. Not all for loops are created equal.Considerfor x in [value1, value2, value3]You would expect to see x vary in the order of the values in the list. However – if x and the values are of an enumerated type, looping the “list” does NOT loop in the apparent order of the constant, but in the order of the enumerated type declaration, such as it would for any set. Example at: https://larsfosdal.blog/2019/02/18/delphi-pitfalls-enumerated-types-and-for-loops/
  21. Lars Fosdal

    Rio 10.3 - IDE Menu|Tabs

    It would have been so nice if the Tabs menu had been sorted by most recently used on top!
  22. Lars Fosdal

    TurboPower component sets sub forums.

    @Daniel - Sounds like a good idea, or what?
  23. Lars Fosdal

    Read of address DEADBEE7. - Source of this raise?

    The question is: Which programmer? What raises the AV?
  24. Lars Fosdal

    Read of address DEADBEE7. - Source of this raise?

    Also spotted: Read of address DEADC00B. Normally I'd expect to see things like this EUseAfterFreeError: Application made attempt to call method of already deleted object: $071EC5A0 OBJECT [TMyClass] 404 bytes.
×